question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Is it possible to call mapStateToProps from a mixin?

See original GitHub issue

I have the redux-todo component which connects the todoApp with the redux store. I also created a mixin from where I would like to inherit some properties and at the same time I would like to connect one of this property to the store from the mixin. I manage to call the mapStateToProps method from the mixin but unfortunately it never bind the property to the store.

Here is what I have so far:

redux-todo.js:

import TodoApp from 'todo-app';
import ReduxMixin from 'mixins/redux';
import { bindActionCreators } from 'polymer-redux';
import { AnotherMixin } from 'another-mixin.js';
import { ExtraMixin } from 'extra-mixin.js';

class ReduxTodo extends AnotherMixin(ExtraMixin(ReduxMixin(TodoApp))) {
	/**
	 * We map any redux state to the element properties here. Feel free to use
	 * libraries like reselect to improve the performance of your app.
	 *
	 * @param {object} state The redux state object.
	 * @param {HTMLElement} element The element instance.
	 *
	 * @return {Object} Key-value map of properties and their values.
	 */

	static get properties() {
		super.properties;
	}

	static mapStateToProps(state, element) {
		super.mapStateToProps(state);
		console.log('mapping props');
		console.dir(state);
		console.dir(this);
		return {
			tasks: state.tasks,
			extras: state.extras,//from extras mixin
			//another: state.another
		};
	}

	constructor(){
		super();
		console.log(this.extras);
		console.log(this.another);
	}

	ready() {
		super.ready();
		// do something that requires access to the shadow tree
		console.log(this.extras);
		console.log(this.another);
		console.log(this.tasks);
		//console.log(this.mapStateToProps);
		;
	  }


	/**
	 * Mapping dispatch to CustomEvents that bubble from internal elements.
	 * This is only called once so make sure you bind correctly.
	 *
	 * Use the exported helper `bindActionCreators` to construct a key-value map
	 * of events that will call `dispatch` with the returning value.
	 *
	 * @param {Function} dispatch The redux dispatch function.
	 * @param {HTMLElement} element The element instance.
	 *
	 * @return {Object} Key-value map of event names and their listeners.
	 */
	static mapDispatchToEvents(dispatch, element) {
		return bindActionCreators(
			{
				addTask(event) {
					return {
						type: 'ADD_TASK',
						task: event.detail
					};
				},
				updateTaskDone(event) {
					return {
						type: 'UPDATE_TASK_DONE',
						index: event.detail.index,
						done: event.detail.done
					};
				},
				removeTask(event) {
					return {
						type: 'REMOVE_TASK',
						index: event.detail
					};
				}
			},
			dispatch
		);
	}
}

customElements.define('redux-todo', ReduxTodo);

another-mixin.js:

import {dedupingMixin} from '@polymer/polymer/lib/utils/mixin.js';
import ReduxMixin from 'mixins/redux';

let internalAnotherMixin = (base) =>
  class extends ReduxMixin(base) {
    static get properties() {
		return {
			another:{
                type:Boolean,
                value: true
            } 
		};
    }
    constructor(){
        super();
        console.log("Hello from another constructor");
        //this.another = true;
    }

    static mapStateToProps(state, element) {
        console.log('mapping props from another-mixin');
        console.dir(this);
        console.dir(state);
		return {
			another: state.another
		};
	}

  }

  export const AnotherMixin = dedupingMixin(internalAnotherMixin);

extra-mixin.js:

import {dedupingMixin} from '@polymer/polymer/lib/utils/mixin.js';

let internalExtraMixin = (base) =>
  class extends base {
    static get properties() {
		return {
			extras: String
		};
    }
    constructor(){
        super();
        console.log("Hello from extras constructor");
        //this.extras = "Hello world";
    }
  }

  export const ExtraMixin = dedupingMixin(internalExtraMixin);

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
craPkitcommented, Jan 29, 2019

@fekitibi I see where you’re coming from. I’m using the same approach for sharing store/prop bindings between different components, but this discussion made me question that.

Anyway, regarding your original question: When you (re-)define mapStateToProps in a mixin and its “subclass”, the latter will override the former. To work around that, you could join the subclass’ result with that of the mixin:

redux-todo.js

static mapStateToProps(state, element) {
  return Object.assign({}, super.mapStateToProps(...arguments), {
    ...subClassPropsMappings
  });
}

another-mixin.js

static mapStateToProps(state, element) {
  return {
    ...mixinPropsMappings
  };
}

Obviously this would need to be implemented in each subclass. Alternatively, you could pass your subclass mappings to the mixin, as a parameter.

redux-todo.js

class extends AnotherMixin(TodoApp, (state, element) => ({
  ...subClassPropsMappings
})) {
  // ...
}

another-mixin.js

export const AnotherMixin = (base, addParamMappings = () => ({})) => class extends base {
  // ...
  static mapStateToProps(state, element) {
    return Object.assign({}, {
      ...subClassProps
    }, addParamMappings(...arguments));
  }
  // ...
}

While this has an off-standard look, I prefer the latter approach, since it delegates mixing in the properties to the, well, mixin.

If you’re working with classical inheritance, the former method might be easier to implement, especially since you can override the method more than once, over multiple hierarchical levels.

1reaction
craPkitcommented, Jan 29, 2019

@tur-nr I think this should not be a discussion whether inheritance or composition is better. Instead, if you want to provide an un-opinionated library, the question should be: how does the toolkit your library is targeting implement similar concepts?

properties are a good example: they are defined almost exactly the same way as mapStateToProps (even though the static non-getter of the latter allows for more customization), and also return a quasi-map. Used in an inheritance-based object model, however, overriding the getter for properties will always add to the existing properties map, never override that of the mixin or base class. That way it doesn’t matter if I inherit or compose my functionality—both will work identically. For me it’s a matter of code consistency!

Things get worse if I’m upgrading from a previous verison of polymer-redux (along with its statePath syntax): Now I have to move all my existing mappings from the base classes (which were once passed down along with their respective properties) and duplicate them to every child class (or implement my rather obscure work-around, everywhere).

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to call mapStateToProps method from a mixin in ...
I manage to call the mapStateToProps method from the mixin but unfortunately it never bind the property to the store.
Read more >
Connect: Extracting Data with mapStateToProps - React Redux
The first argument to a mapStateToProps function is the entire Redux store state (the same value returned by a call to store.getState() )....
Read more >
Is it possible to define a ReactJS Mixin method that can be ...
Coding example for the question Is it possible to define a ReactJS Mixin method ... a unit test for a react component that...
Read more >
polymer3-redux - npm Package Health Analysis - Snyk
This factory function is used to create a Redux mixin for Polymer ... Redux mixin can now implement static mapStateToProps(state, element) .
Read more >
Flight.js in 2016 - Tom Ashworth
Like React, we consider mixins harmful. However, as they are almost the only way to extend Flight core in a modular way, we...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found