Understanding React props - reactjs

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.

Related

Make AJAX request when the property was changed

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/

Caching the value of a method in react component

I'm coming from an Ember background which had computed properties that were lazily computed and then cached until the dependent properties change.
Say I have the following setup in react:
export default React.createClass({
getInitialState: function(){
return {
firstName: 'John',
lastName: 'Smith'
}
},
fullName: function(){
console.log('full name is computed')
return `${this.state.firstName} ${this.state.lastName}`;
},
changeFirstName: function(){
this.setState({ firstName: 'somethingElse'});
},
changeUnrelatedState: function(){
this.setState({ blah: 'zzzzzz' });
},
render: function(){
return (
<div>{this.state.firstName} and {this.state.lastName} makes {this.fullName()}</div>
<button onClick={this.changeFirstName}>Change first name</button
<button onClick={this.changeUnrelatedState}>Change some state variable</button
);
}
});
When I click the 'Change some state variable' button, the component re-renders and the fullName method recomputes. This is a simple example, but what if the fullName method performed an expensive computation? This would run every single time the state changes, regardless of whether or not firstName or lastName changed but still triggering that expensive operation.
Is there a react way of caching the value of a method, and not re-computing it during each render?
By extracting our expensive computation into a new component we can implement shouldComponentUpdate and only recalculate when needed. This way we get "caching" of already once computed values.
var FullNameComponent = React.createClass({
shouldComponentUpdate: function (nextProps, nextState) {
//Props was the same no need for re-rendering
if (nextProps.firstName === this.props.firstName) return false;
//Props has changed, recalculate!
return true;
},
performExpensiveCalculation: function () {
console.log('rerenders');
return `${this.props.firstName} ${this.props.lastName}`;
},
render: function () {
return (<div>{this.performExpensiveCalculation()}</div>);
}
});

ReactJS: best practice access input values when creating forms

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

can i use action in Flux to control routes, HOW?

I am writing a authentication module in Flux, actions : auth,auth_success,auth_error. I am thinking when action auth_error occur, the router will go to '/login'. When action, action, auth_success occur, the router will go to '/dashboard'.
But it seems to be wrong because action only goes to dispatcher. I don't know how to do route the callbacks. Maybe check the store value?
You have to mixin your React class with Route.Navigation object, for instace
/** #jsx React.DOM */
var React = require('react');
var Router = require('react-router')
, Navigation = Router.Navigation;
var UserStore = require('user-store');
var YourClass = module.exports = React.createClass({
mixins:[Navigation], //This is very important
getInitialState: function() {
return {};
},
componentWillMount: function(){
UserStore.addChangeListener(this._method);
},
componentWillUnmount: function(){
UserStore.removeChangeListener(this._method);
},
render: function() {
return (
<div>
</div>
);
},
_method: function() {
// From here you can call methods of Navigator Object
this.transitionTo('SomeRouteName'); //This method will render the specified <Route>
}
});
For further information you can check
https://github.com/rackt/react-router/blob/master/docs/api/mixins/Navigation.md
In order to change the route and according to flux architecture, you should call transitionTo from a callback of some User Store you should have.
I added an example to the code, you may customise it to your specific case.
Happy coding!

How to freely use pojo's, having setters, as state in React

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."

Resources