-
Notifications
You must be signed in to change notification settings - Fork 149
Thoughts on explicitly enforcing the Flux pattern #55
Description
I just wanted to throw some thoughts out there and see what you guys think. Some of these were brought up in #10.
Removing this.context dependency
The FluxChildMixin relies on receiving the flux object via this.context which React passes to the components automatically. There are a few good reasons this should be avoided.
- Since contexts are intentionally not documented and subject to change, there are a lot of context-related BC's going at the main repo.
- Context is only passed to children that are rendered within the
render()method. Here's an example of how context gets lost. AndcloneWithProps()doesn't copy context or owner. This is problematic since lots of React-based repos use it. For example when usingModalTriggerin react-bootstrap, the context doesn't get passed to theModalcomponents. To get around this you can explicitly pass in thefluxobject, but my point is that should be done all the time (see next section). :) - One nice aspect of the "React way" is the explicit idiomatic propagation of dependancies down the component tree. Having a dependency magically handled for you in the background seems to be an anti-pattern to both React's philosophy and the Flux pattern.
Explicitly passing stores and actions to components
Since the root controller-view is the only component that needs to watch for changes of the state of the store, the store should be explicitly passed to it exclusively. The actions would be passed as a separate prop (or props) and could be further passed down the component tree exclusively.
var ChildComponent = React.createClass({
propTypes: {
myActions: React.PropTypes.object.isRequired,
immutableStoreState: React.PropTypes.object.isRequired
},
doSomething: function() {
if(this.props.immutableStoreState.readOnlyThing) {
return this.props.myActions['FooActions'].someAction();
}
return this.props.myActions['FooActions'].someOtherThing();
},
render: function() {
return (
<div>
<h2>Child Component</h2>
<p onClick={this.doSomething}>Click me</p>
</div>
);
}
});
var StoreWatchMixin = Fluxxor.StoreWatchMixin;
var RootControllerView = React.createClass({
mixins: [StoreWatchMixin("FooStore")],
propTypes: {
myStores: React.PropTypes.object.isRequired,
myActions: React.PropTypes.object.isRequired
},
getStateFromFlux: function() {
return this.props.myStores['FooStore'].getState();
},
render: function() {
return (
<div>
<h1>My App</h1>
<ChildComponent myActions={this.props.myActions} immutableStoreState={this.getStateFromFlux()} />
</div>
);
}
});
var flux = new Fluxxor.Flux(storesObject, actionsObject),
stores = flux.getStores(),
actions = flux.getActions();
React.renderComponent(
<RootControllerView myStores={stores} myActions={actions} />,
document.getElementById('my-app')
);The StoreWatchMixin is really nice since it's pretty strictly Flux and you can learn the "Flux way" of handling the store state by examining the mixin source code.
This would eliminate the need to have FluxMixin and FluxChildMixin and thus the this.context dependency. We might still need to pass in the flux object for the StoreWatchMixin.
Fluxxor's Role
I guess the real question is what role does Fluxxor want to take? Is it designed to help enforce a strict Flux architecture? If so, people who want to better understand Flux by using this package would really benefit from the points above.
I'd love to hear your thoughts. :)