I've been playing a bit with ReactJS and am really enjoying the framework.
I'm also trying to follow the rule of creating components that are stateless where possible.
I have a Settings component that includes a child SettingsForm and a SettingsWidget.
Settings holds all the states, and only pass it as props to the form and widget.
This works (and scales) well because when the state in Settings is updated, it propagates to all child components.
var Settings = React.createClass({
getInitialState: function() {
settings: {}
}
})
What I am not 100% sure on is the best practice when accessing input values on SettingsForm to pass it on to the parent component.
I know I can use refs and also two-way binding to accomplish this, but neither feel very "ReactJS-like".
Is there a better of way accomplishing this that I am unaware of? For the sake of completeness, I've included the relevant code in my SettingsForm component below
var SettingsForm = React.createClass({
getInitialState: function() {
return {
changed: false
}
},
handleChange: function(event) {
this.setState({changed: true})
this.props.handleChange(
this.refs.emailInputFieldRef.getDOMNode().value,
this.refs.firstNameInputFieldRef.getDOMNode().value
)
},
handleSubmit: function(event) {
event.preventDefault();
// Access and pass on input values to parent callback so state is updated
this.props.handleUpdate(
this.refs.emailInputFieldRef.getDOMNode().value,
this.refs.firstNameInputFieldRef.getDOMNode().value
)
this.setState(this.getInitialState());
},
...
}
For now there is a Mixin you can use to link the input values to the state, called LinkedStateMixin that is exactly what you are looking for...
var WithLink = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function() {
return <input type="text" valueLink={this.linkState('message')} />;
}
});
Then all you have to do is modify your handler functions on the parent component to take your inputs as variables, and pass that function down to the child component as a prop. When you want to handle the form, call that function in the props and send the state (bound with from the Mixin) as the variables.
React Docs - React Link
Related
I would like to have a component, which get the property from parent component and make an AJAX request, based on this propery. The parent component can change this property and my child component must get another one AJAX request.
Here is my code, but I am not sure it is optimal and even correct:
<News source={this.state.currentSource} />
Component:
var News = React.createClass({
propTypes: {
source: React.PropTypes.string
},
getInitialState: function() {
return {
entities: []
};
},
componentWillReceiveProps(nextProps) {
var url = 'http://localhost:3000/api/sources/' + nextProps.source + '/news';
this.serverRequest = $.get(url, function(result) {
this.setState({
entities: result
});
}.bind(this));
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
// ...
}});
module.exports = News;
Does componentWillReceiveProps is a good place for this code?
componentWillReceiveProps will work just fine, one thing I would do differently is if <News/> is getting its props from a parent component then a good pattern to follow is to have the parent component actually handle the api calls and pass down the results as props. This way your News component really only has to deal with rendering content based on its props vs rendering and managing state.
I can only see limited portion of your App so that might not fit your use case but here is a great article on doing that type of differentiation between smart and dumb components.
http://jaketrent.com/post/smart-dumb-components-react/
Looking at Facebook's react example here, I found this code showing how to use mixins to set intervals. I am confused as to what is happening with this.intervals. I understand that state holds render-altering data, and props handle data handed down from a parent component, ideally. I would have used this.props.intervals instead, but what is the difference between the two?
var SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.forEach(clearInterval);
}
};
var TickTock = React.createClass({
mixins: [SetIntervalMixin], // Use the mixin
getInitialState: function() {
return {seconds: 0};
},
componentDidMount: function() {
this.setInterval(this.tick, 1000); // Call a method on the mixin
},
tick: function() {
this.setState({seconds: this.state.seconds + 1});
},
render: function() {
return (
<p>
React has been running for {this.state.seconds} seconds.
</p>
);
}
});
ReactDOM.render(
<TickTock />,
document.getElementById('example')
);
When you use props, you know for 100% certainty the value should will be coming from it's immediate parent component (as a property).
When you see state, you know the value is being born/created within that component it's self.
The key, when state changes, every child below will render if any of their received props change.
Your Mixin is not a normal React class. It is simply an object, so this in the case of this.interval, is a reference to the scope of the object in which the method is being executed - TickTock.
I'm creating several React Components that behave in the same way except of rendering data. I put similar logic into mixin, including render function. The only thing I pass is the additional component that is responsible for presenting data in required way.
var A = React.createClass({
mixins: [MyMixin],
MyComponent: B,
});
var B = React.createClass({
get_value: function() {
// should return some value using top-level context
},
render: function() {
var x = this.get_value()
}
})
MyMixin = {
// some logic
render: function() {
<div>
// some common markup
<this.MyComponent
// some props
/>
</div>
}
}
The problem here is that component B (which is rendered through variable in mixin) doesn't have top-level context, from parents. At the same time components in the 'common markup' block does have it. How could I render components in the way above and save top-level context?
You can't access the top level context because B is not inheriting or sharing anything with A. Your mixin is just a simple extension of shared functionality and you just render component defined in component A. There is nothing that binds A and B.
What you could do is pass the needed stuff in the props of B.
<div>
// some common markup
<this.MyComponent
parentProps={this.props}
parentState={this.state}
/>
</div>
What you really should do is add all the common code in the mixin and use that mixin in both of your components. Since render is NOT common for your components you should define the render in each component or make an other mixin for that purpose.
Hitting a roadbump, I’m seeking some help. I'm starting to move more of my "state" pojo's out of my React components, due to for example being unsure how how my pojo’s setter methods should be utilized now (one may want setter methods to validate, etc.). I now find myself either defying React docs' warning to NEVER touch this.state directly or moving most code except rendering – including state - outside of the React component into my own js variables/objects (and holding a reference to the rendered object then using forceUpdate() to rerender). What is the recommended way to freely use whatever plain old js data/model objects I want, including with setter methods?
This barebones example, where I’m wanting a form-backing data object, demonstrates this difference I’m facing: http://jsfiddle.net/jL0rf0ed/ vs. http://jsfiddle.net/rzuswg9x/. Also pasted the code for the first below.
At the very least, I have this specific question: following a custom/manual update of this.state, does a this.setState(this.state) line, which would be from within the React component, and a component.forceUpdate() line, which would likely be from outside the React component, work just as fast and correctly as the standard this.setState({someKey: someValue})?
Thanks.
//props: dataObj, handleInputChange
test.ComponentA = React.createClass({
getInitialState: function() {
return {
age: 21,
email: 'a#b.com', //TODO make members private
setEmail: function(val) { //TODO utilize this
this.email = val;
if(val.indexOf('#') == -1) {
//TODO set or report an error
}
}
}
},
handleInputChange: function(e) {
this.state[e.target.name]=e.target.value; //defying the "NEVER touch this.state" warning (but it appears to work fine)!
this.setState(this.state); //and then this strange line
},
render: function() {
return (
<div>
<input type='text' name='age' onChange={this.handleInputChange} value={this.state.age}></input>
<input type='text' name='email' onChange={this.handleInputChange} value={this.state.email}></input>
<div>{JSON.stringify(this.state)}</div>
</div>
);
}
});
React.render(<test.ComponentA />, document.body);
For your code example in your pasted snippet, you can do the following.
handleInputChange: function(e) {
var updates = {};
updates[e.target.name] = e.target.value;
this.setState(updates);
},
In your second example, you should never call forceUpdate or setState from outside the component itself. The correct way would be for the state to be contained in whatever renders your component and pass in the data as props.
Usually this means you have a wrapper component.
var RootComponent = React.createClass({
getInitialState: ...
onInputChange: function() {
this.setState({yourKey: yourValue});
},
render: function() {
return <SubComponent yourKey={this.state.yourKey} onInputChange={this.onInputChange} />;
}
};
In your case, I would recommend creating this wrapper component. Another solution is just to rerender the same component into the same DOM node.
test.handleInputChange = function(e) {
// update test.formPojo1 here
React.render(<test.ComponentA dataObj={test.formPojo1} handleInputChange={...} />);
}
Because it is the same component class and DOM node, React will treat it as an update.
Stores
Facebook uses the concept of a Store in their Flux architecture.
Stores are a very targeted POJO. And I find that it is pretty simple to use the Store metaphors without the using the entirety of Flux.
Sample Store
This is a Store that I pulled out of one of our production React apps:
ChatMessageStore = {
chatMessages: [],
callbacks: [],
getAll: function() {
return this.chatMessages;
},
init: function() {
this.chatMessages = window.chat_messages.slice();
return this.emitChange();
},
create: function(message) {
this.chatMessages.push(message);
return this.emitChange();
},
emitChange: function() {
return this.callbacks.forEach(callback, function() {
return callback();
});
},
addChangeListener: function(callback) {
return this.callbacks.push(callback);
},
removeChangeListener: function(callback) {
return this.callbacks = _.without(this.callbacks, callback);
}
};
Hooking it up to a React Component
In your component you can now query the store for its data:
var Chat = React.createClass({
componentWillMount: function() {
return ChatMessageStore.addChangeListener(this._onChange);
},
componentWillUnmount: function() {
return ChatMessageStore.removeChangeListener(this._onChange);
},
getInitialState: function() {
return this.getMessageState();
},
getMessageState: function() {
return {
messages: ChatMessageStore.getAll()
};
}
});
The Component registers a callback with the Store, which is fired on every change, updating the component and obeying the law of "don't modify state."
This may be treading that line between answerable and opinionated, but I'm going back and forth as to how to structure a ReactJS component as complexity grows and could use some direction.
Coming from AngularJS, I want to pass my model into the component as a property and have the component modify the model directly. Or should I be splitting the model up into various state properties and compiling it back together when sending back upstream? What is the ReactJS way?
Take the example of a blog post editor. Trying to modify the model directly ends up looking like:
var PostEditor = React.createClass({
updateText: function(e) {
var text = e.target.value;
this.props.post.text = text;
this.forceUpdate();
},
render: function() {
return (
<input value={this.props.post.text} onChange={this.updateText}/>
<button onClick={this.props.post.save}/>Save</button>
);
}
});
Which seems wrong.
Is it more the React way to make our text model property state, and compile it back into the model before saving like:
var PostEditor = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
componentWillMount: function() {
this.setState({
text: this.props.post.text
});
},
updateText: function(e) {
this.setState({
text: e.target.value
});
},
savePost: function() {
this.props.post.text = this.state.text;
this.props.post.save();
},
render: function() {
return (
<input value={this.state.text} onChange={this.updateText}/>
<button onClick={this.savePost}/>Save</button>
);
}
});
This doesn't require a call to this.forceUpdate(), but as the model grows, (a post may have an author, subject, tags, comments, ratings, etc...) the component starts getting really complicated.
Is the first method with ReactLink the way to go?
Updating 2016:
React is changed, and explanation "props vs state" became very simple. If a component needs to change data - put it in a state, otherwise in props. Because props are read-only now.
What's the exact difference between props and state?
You can find good explanation here (full version)
Your second approach is more like it. React doesn't care about models so much as it cares about values and how they flow through your app. Ideally, your post model would be stored in a single component at the root. You then create child components that each consume parts of the model.
You can pass callbacks down to the children that need to modify your data, and call them from the child component.
Modifying this.props or this.state directly is not a good idea, because React will not be able to pick up on the changes. That's because React does a shallow comparison of your post prop to determine if it has changed.
I made this jsfiddle to show how data could flow from an outer to an inner component.
The handleClick method shows 3 ways to (im)properly update state:
var Outer = React.createClass({
getInitialState: function() {
return {data: {value: 'at first, it works'}};
},
handleClick: function () {
// 1. This doesn't work, render is not triggered.
// Never set state directly because the updated values
// can still be read, which can lead to unexpected behavior.
this.state.data.value = 'but React will never know!';
// 2. This works, because we use setState
var newData = {value: 'it works 2'};
this.setState({data: newData});
// 3. Alternatively you can use React's immutability helpers
// to update more complex models.
// Read more: http://facebook.github.io/react/docs/update.html
var newState = React.addons.update(this.state, {
data: {value: {$set: 'it works'}}
});
this.setState(newState);
},
render: function() {
return <Inner data={this.state.data} handleClick={this.handleClick} />;
}
});
From React doc
props are immutable: they are passed from the parent and are "owned" by the parent. To implement interactions, we introduce mutable state to the component. this.state is private to the component and can be changed by calling this.setState(). When the state is updated, the component re-renders itself.
From TrySpace: when props (or state) are updated (via setProps/setState or parent) the component re-renders as well.
A reading from Thinking in React:
Let's go through each one and figure out which one is state. Simply
ask three questions about each piece of data:
Is it passed in from a parent via props? If so, it probably isn't
state.
Does it change over time? If not, it probably isn't state.
Can you compute it based on any other state or props in your
component? If so, it's not state.
I'm not sure if I'm answering your question, but I've found that, especially in a large/growing application, the Container/Component pattern works incredibly well.
Essentially you have two React components:
a "pure" display component, which deals with styling and DOM interaction;
a container component, which deals with accessing/saving external data, managing state, and rendering the display component.
Example
N.B. This example is a probably too simple to illustrate the benefits of this pattern, as it is quite verbose for such a straightforward case.
/**
* Container Component
*
* - Manages component state
* - Does plumbing of data fetching/saving
*/
var PostEditorContainer = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
componentWillMount: function() {
this.setState({
text: getPostText()
});
},
updateText: function(text) {
this.setState({
text: text
});
},
savePost: function() {
savePostText(this.state.text);
},
render: function() {
return (
<PostEditor
text={this.state.text}
onChange={this.updateText.bind(this)}
onSave={this.savePost.bind(this)}
/>
);
}
});
/**
* Pure Display Component
*
* - Calculates styling based on passed properties
* - Often just a render method
* - Uses methods passed in from container to announce changes
*/
var PostEditor = React.createClass({
render: function() {
return (
<div>
<input type="text" value={this.props.text} onChange={this.props.onChange} />
<button type="button" onClick={this.props.onSave} />
</div>
);
}
});
Benefits
By keeping display logic and data/state management separate, you have a re-usable display component which:
can easily be iterated with different sets of props using something like react-component-playground
can be wrapped with a different container for different behavior (or combine with other components to build larger parts of your application
You also have a container component which deals with all external communication. This should make it easier to be flexible about the way you access your data if you make any serious changes later on*.
This pattern also makes writing and implementing unit tests a lot more straightforward.
Having iterated a large React app a few times, I've found that this pattern keeps things relatively painless, especially when you have larger components with calculated styles or complicated DOM interactions.
*Read up on the flux pattern, and take a look at Marty.js, which largely inspired this answer (and I have been using a lot lately) Redux (and react-redux), which implement this pattern extremely well.
Note for those reading this in 2018 or later:
React has evolved quite a bit since this answer was written, especially with the introduction of Hooks. However, the underlying state management logic from this example remains the same, and more importantly, the benefits that you get from keeping your state and presentation logic separate still apply in the same ways.
I think you're using an anti-pattern which Facebook has already explained at this link
Here's thing you're finding:
React.createClass({
getInitialState: function() {
return { value: { foo: 'bar' } };
},
onClick: function() {
var value = this.state.value;
value.foo += 'bar'; // ANTI-PATTERN!
this.setState({ value: value });
},
render: function() {
return (
<div>
<InnerComponent value={this.state.value} />
<a onClick={this.onClick}>Click me</a>
</div>
);
}
});
The first time the inner component gets rendered, it will have { foo: 'bar' } as the value prop. If the user clicks on the anchor, the parent component's state will get updated to { value: { foo: 'barbar' } }, triggering the re-rendering process of the inner component, which will receive { foo: 'barbar' } as the new value for the prop.
The problem is that since the parent and inner components share a reference to the same object, when the object gets mutated on line 2 of the onClick function, the prop the inner component had will change. So, when the re-rendering process starts, and shouldComponentUpdate gets invoked, this.props.value.foo will be equal to nextProps.value.foo, because in fact, this.props.value references the same object as nextProps.value.
Consequently, since we'll miss the change on the prop and short circuit the re-rendering process, the UI won't get updated from 'bar' to 'barbar'