I'm learning to use backbone and react. I'm using react as the V in MV* and backbone for Model.
But there's a problem: I passed a backbone collection to a react component, when I add more models to this collection, react is not updating.
And if I listen on collection changing event and call react method: forceUpdate, react will reflect the changes.
So I guess react is not aware of the changes happened in the collection object.
How can I make react automatically update with backbone?
React doesn't have any native way to listen to Backbone events of any kind. It's entirely unaware of your Backbone code. Solving this depends entirely on how you want to architect your solution.
1) You could simply manually wire up Backbone events to your component's forceUpate() on component initialization:
React.createClass(
{
componentWillMount: function()
{
// For models:
this.props.model.on("change", this.forceUpdate);
// For collections:
this.props.collection.on("change", this.forceUpdate);
this.props.collection.on("add", this.forceUpdate);
this.props.collection.on("remove", this.forceUpdate);
this.props.collection.on("reset", this.forceUpdate);
}
});
2) You could write a mixin that copies Model or Collection properties into the React component's state, and calls setState on Model/Collection changes:
3) You could use an existing Mixin like React.Backbone: https://github.com/usepropeller/react.backbone
Related
I'm working with AngularJS 1.6 and a component based web application. I'm building a new component which contains a table and on selecting a row another stateless component is being displayed with detailed information about that rows' object (the row is passe down via '<'-binding). So far, it works. I'm using stateful and stateless components, and from Todd Motto I learned to use one way binding (also in preparation to migrate to Angular) and that to break JavaScripts' bind-by-reference I should use following event hook in the stateless component (the detail component in my specific case):
ctrl.$onChange = function(changes) {
if (changes.row) {
this.row = angular.copy(this.row);
}
};
It does work in the sense that changes in the child component do not change the object in the parent component anymore, cause the bind-by-reference is broken.
Problem is: If I select another row in the table, the changed object is NOT being passed down anymore, the stateless component does not "recognize" a changed object in the binding! If I ommit the above code it works, but will it still work when migrating to Angular? What should I do?
Copy the changes:
ctrl.$onChange = function(changes) {
if (changes.row) {
̶t̶h̶i̶s̶.̶r̶o̶w̶ ̶=̶ ̶a̶n̶g̶u̶l̶a̶r̶.̶c̶o̶p̶y̶(̶t̶h̶i̶s̶.̶r̶o̶w̶)̶;̶
this.row = angular.copy(changes.row.currentValue);
}
};
From the Docs:
Life-cycle hooks
Directive controllers can provide the following methods that are called by AngularJS at points in the life-cycle of the directive:
$onChanges(changesObj) - Called whenever one-way (<) or interpolation (#) bindings are updated. The changesObj is a hash whose keys are the names of the bound properties that have changed, and the values are an object of the form { currentValue, previousValue, isFirstChange() }. Use this hook to trigger updates within a component such as cloning the bound value to prevent accidental mutation of the outer value. Note that this will also be called when your bindings are initialized.
For more information, see
AngularJS Comprehensive Directive API Reference - Life-Cycle Hooks
I'm creating a React Native app and I want to add observable/observer pattern but the observer's render function is not re-executing when the observable changes.
Here is the store where the observable is:
https://github.com/ksairi/GalaApp/blob/development/app/stores/NotificationsStore.js
This is the stores' index file:
https://github.com/ksairi/GalaApp/blob/development/app/stores/index.js
This is the screen where the observer is and this specific line in the render function is the one that should make the render to re-execute again but is not happening.
https://github.com/ksairi/GalaApp/blob/development/app/screens/Notifications.js#L86
Any ideas?
I am using react and flux in my application, In my application I have two components: TreeView and TableView and their is fetched from two different stores.
I want to add an option - when I click on a row in my TableView it will open the relevant node in my TreeView.
My question is: How those two components should talk to each other? In AngularJS/Backbone I will use an Event Aggreator pattern and will broadcast an event like - "objectSelected" with it's id.
How should I do this in react with flux architecture - I thought using the flux way - and creating an action, but then my store will save UI state (which nodes are open) and I think that the component (in this case TreeView) should save this state (and not the store).
So what's the correct for talking between two components in react?
If you don't want to use flux, then you would pass actions as props through a parent component.
The only flux implementation I've used is Fluxxor. Using fluxxor (and probably most flux implementations) you can have both a component state and a store state. If your table and tree are always going to be linked (both open or closed at the same time), I think it would be okay to save it in a store.
You might do something like ..
TableComponent = React.createClass({
getInitialState: function() {
return {
//component specific state
};
},
getStateFromFlux: function() {
// flux store state
return {
appStore: this.getFlux().store('AppStore').state
}
},
handleClick: function(tree) {
this.getFlux().actions.appActions.toggleTree(tree);
}
});
If that the flux store is a singleton that maintains the state of the data why do the components use setState and not setProps when accessing the stores? Wouldn't it just mean that I started saving the application state in two (or more) places?
Both the Flux / React documentation and Examples seem to point to setState as the preferred solution, but I've had an interesting conversation with a few colleagues at work and wondered if anyone else came across this
Edit:
You can see what I'm talking about in this url:
https://github.com/facebook/flux/blob/master/examples/flux-chat/js/components/ThreadSection.react.js
Notice how ThreadSection is a child component, that is fetching data directly from a store and using it as a state.
If you follow the React "way" I would have expected the state to be managed by the store - not a child component.
The solution we thought of is to fetch all stores in the top level component (as props) and pass them down to the child components as needed. But that gets rather ugly rather quickly.
We do that because setProps does not work on child components
Understand that you should have 2 kinds of components. Stateful components and view components.
Stateful components can have 3 kinds of states: initial state, user input state, and data store state.
Stateful components are like small entry points in the "widget" that you're assembling. There is no single application-wide entry point anymore for downstream dependency or data injection, because all of these widgets have their own isolated lifecycles. That's why they themselves need to access & listen to stores.
Besides behavorial properties, stateful components do not receive actual data via upstream properties.
Stateful components manage their own state and pass it to their children to render through downstream properties.
Stateful components do not normally render html DOM elements themselves directly. They're more like the controllers in MVC, and use other dumber components, the ones like views in MVC, to actually render DOM elements.
Dumber components are like views so they only contain logic to render DOM elements. Think of them as handlebars.js templates that only receive properties, and simply render those into DOM elements possibly with loops etc. They are stateless renderers.
Hope this answers your question.
According to formal documentation, a store should update the parent component's state, and pass it down via his children props:
When it receives the event from the store, it first requests the new data it needs via the stores' public getter methods. It then calls its own setState() or forceUpdate() methods, causing its render() method and the render() method of all its descendants to run.
We often pass the entire state of the store down the chain of views in a single object, allowing different descendants to use what they need. In addition to keeping the controller-like behavior at the top of the hierarchy, and thus keeping our descendant views as functionally pure as possible, passing down the entire state of the store in a single object also has the effect of reducing the number of props we need to manage.
(facebook flux docs - Overview)
It makes more sense to put store data in the component's state, this is because props may change by a parent component with componentWillReceiveProps. So it makes sense to update the state whenever:
the store's change event is fired and
whenever the props change (putting derivative data related only to the component itself to the state)
Below is a sample component that updates listening to a reflux store and also on props change. I rarely use this.props in the render function, instead I amend them (create derivative data that is only used within the component itself) as new props come in. I constantly run into this pattern so might as well write this down:
var SampleComponent = React.createClass({
mixins: [Reflux.ListenerMixin],
// reusable helper function to build state object
buildStateFromProps: function(props) {
return {
actualHeight: props.height + 20
}
},
// default props if no such was set by a parent component
getDefaultProps: function() {
return {
height: 100
};
},
// initial state with all value set to something default
// even using buildStateFromProps with default props
getInitialState: function() {
// this.props is built before this.state
var state = buildStateFromProps(this.props);
// append default data from store
state.text = '';
},
// happens when the parent component send different
// props data
componentWillReceiveProps: function(nextProps) {
// building derivative data from new props
// reusing buildStateFromProps
this.setState(buildStateFromProps(nextProps));
},
// setting up store to be used by the component
componentDidMount: function() {
// this.listenTo is a helper function ListenerMixin
this.listenTo(sampleStore, sampleUpdated);
},
// is called from the sampleStore update
sampleUpdated: function(sampleData) {
this.setState({
text: sampleData.text
});
},
render: function() {
return (
// ...
// using this.state.text from store updates and
// this.state.height from prop updates
);
}
});
The reason I send props data to state is to avoid cluttering up the render function. Otherwise the render function will contain a lot of code that is not really related to "rendering" the component. Furthermore if this derivative data is used in other parts of the application then it is easy to pull it out from the component and put it into the store.
Hope this helps.
A valid answer to this question sits hidden in the comments to a previous answer:
#idolize you can also pass stores in using React contexts (a hidden,
not yet officially documented feature). It's really nice because you
don't have to do all that passing down the hierarchy. There are a few
articles about contexts, search for it online! – Andy Jul 17 '15 at
18:41
I have a react component for a list of data comprised of two sub components
<List>
<SortingAndFiltering data={this.state.data}/>
<RowsDisplay data={this.state.data}/>
</List>
One subcomponent handles sorts and filters and the other renders the actual bulk of the data.
When I perform a sort on the props.data inside SortingAndFiltering the event isn't propagated up the chain.
Whats the correct way to signal that a consumer of a prop has made a change to this prop?
React doesn’t do two-way data bindings by default and for good reasons.
However, there is an add-on called ReactLink that could be of use: http://facebook.github.io/react/docs/two-way-binding-helpers.html
If you are using Backbone as data models, there are mixins that provide listeners for model changes that can re-render the app when signals are received from anywhere in the hierarchy.
To dig deeper regarding unidirectional data flow, I recommend this video that explains the Flux concept used by Facebook: http://facebook.github.io/react/docs/flux-overview.html
checkout http://facebook.github.io/react/docs/thinking-in-react.html step 5,which is similar to yours.