Permalink
..
Failed to load latest commit information.
README.md addition of Reflux.PureComponent Feb 28, 2017

README.md

Reflux.Component Documentation

Overview

Of course, a main point of actions and stores is to eventually tie the data being stored/manipulated in them into a React component.

For that Reflux gives you Reflux.Component and Reflux.PureComponent. Reflux.Component is itself an extension of React.Component that was created to facilitate hooking stores into the component. You would use a Reflux.Component the exact same as a React.Component, except that you'd use its specific properties and methods to hook in the state of your stores. Reflux.PureComponent is used the exact same, except it inherits the same behavior as React.PureComponent as for shallow checking state to see if updates are needed.

Mixing State with this.store and this.stores

The main declarative way to utilize one or more stores within a Reflux.Component is this.store (assign one store) or this.stores (assign an Array of stores).

class Counter extends Reflux.Component // <-- note Reflux.Component, not React.Component
{
	constructor(props)
	{
		super(props);
		this.store = CountStore; // <-- a store w/state with a `count` property
	}
	
	render()
	{
		// since CountStore has a state.count, now this component shares it
		return <div>Count: {this.state.count}</div>
	}
}

The count property from the store is mixed into the component's state. It acts just like a normal part of the state within the component. As setState is used to change the value within the store the state within the component is updated and the component is re-rendered, shouldComponentUpdate works as normal, etc.

Note that you assign the class itself. Reflux will automatically either A) make a singleton instance of it, or B) use a preexisting singleton if one already has been made. It is possible to assign an instance created from a Reflux.Store class, however it is practically always preferrable to simply assign the class itself so that Reflux can manage the singleton properly.

Normal state properties are also preserved. You may use state from the component itself and state from one or more stores side-by-side:

class Counter extends Reflux.Component
{
	constructor(props)
	{
		super(props);
		this.stores = [CountStore, MultiplierStore];
		this.state = {offset: 5};
	}
	
	render()
	{
		// the state props come from the CounterStore, MultiplierStore, and normal state
		var calculatedValue = this.state.count * this.state.multiplier + this.state.offset;
		return <div>Count: {calculatedValue}</div>
	}
}

Limiting Mixing with this.storeKeys

By default, the entire store is mixed into your component. However, it is very useful to be able to easily bring in only part of the store. This prevents A) unintended name conflicts, such as a store state property added after-the-fact overwriting a piece of normal in-component state accidentally, and B) unneeded rendering, since some components may only need certain parts of the store and therefore do not need to re-render every time other properties update.

This is what this.storeKeys is for. It allows you to assign an Array of strings, and only property key names from that Array will be taken from any stores mixed in via this.store or this.stores.

class Counter extends Reflux.Component
{
	constructor(props)
	{
		super(props);
		this.store = CountStore;
		this.storeKeys = ['count']; // <-- only `count` will be mixed in from the store
	}
	
	render()
	{
		return <div>Count: {this.state.count}</div>
	}
}

Manually Mapping States with this.mapStoreToState

In addition to the more declarative ways to merge store state into a component that are described above (i.e. this.store, this.stores, this.storeKeys) there is another more imperative style for merging state. That is the Reflux.mapStoreToState method that is part of Reflux stores.

An important thing to note is that this is completely separate from the previously mentioned declarative side of things (such as this.store). You should not have the same store attached to a component both via this.store and using this.mapStoreToState. This method is also completely unaffected by this.storeKeys. These differing methods can both be used within a single component, but just shouldn't both be used for the same store within the same component.

this.mapStoreToState takes 2 arguments: the store you want mapped to the component state, and a mapping function supplied by you. The mapping function will be called any time the store's this.setState is used to change the state of the store. The mapping function takes an argument which will be the state change object from the store for that particular change. It needs to return an object which will then be mapped to the component state (similar to if that very returned object were used in the component's this.setState). If an object with no properties is returned then the component will not re-render. The mapping function is also called with its this keyword representing the component, so comparing store values to current component state values via this.state is possible as well.

class MyComponent extends Reflux.Component
{
	constructor(props)
	{
		super(props);
		
		this.mapStoreToState(MyStoreClass, function(fromStore){
			var obj = {};
			if (fromStore.color)
				obj.color = fromStore.color;
			if (fromStore.data && fromStore.data.classToUse)
				obj.class = fromStore.data.classToUse;
			return obj;
		});
	}
	
	render()
	{
		return <p className={this.state.class}>The color is: {this.state.color}</p>;
	}
}

Note that the fromStore in the example above may not always be the full state from the store. It only receives what is actually changing at that time. This way you are able to only map the parts of the store that have actually changed on each call.

Extending a 3rd Party Class with Reflux.Component.extend

Sometimes 3rd party libraries will have their own class that extends React.Component that they require you to use. Reflux handles this by exposing the Reflux.Component.extend method. If you have such a 3rd party class you can pass that class to this method and it will return a version of Reflux.Component that extends it instead of extending React.Component directly. Example:

import {ThirdPartyComponent} from 'third-party';

var RefluxThirdPartyComponent = Reflux.Component.extend(ThirdPartyComponent);

class MyComponent extends RefluxThirdPartyComponent
{
    // ...
}

componentWillMount and componentWillUnmount

The Reflux.Component class utilizes both the componentWillMount and componentWillUnmount methods in the React lifecycle. This means that any extension you create that uses these methods will override those methods within the Reflux.Component class you're extending. If you run into this problem the solution is simple: just run the appropriate super. For example, in a componentWillMount:

	// ...
	
	componentWillMount()
	{
		// ... your stuff ...
		
		super.componentWillMount();
	}
	
	//...

More:

Learn about Reflux Stores and Actions, or go back to the overview of the docs.