There are 3 react components, two of them inside of the first. The first component contains some state which used only in third component. When I update state from third component with callback react additionally update second component. But second component have no changes.
Why does this happen and how to avoid it?
here is my code:
var app = React.createClass({
displayName: 'app',
settingsChanged: function (value) {
console.log('app.settingsChanged');
this.setState({ settings: { value: value } });
},
getInitialState: function() {
return { settings: { value: 1 } }
},
render: function() {
return (
React.createElement('div', null,
React.createElement(component1),
React.createElement(component2, { settings: this.state.settings, settingsChanged: this.settingsChanged })
)
);
}
})
var component1 = React.createClass({
displayName: 'component1',
render: function () {
console.log('component1.render');
return (
React.createElement('div', null, 'component1')
);
}
})
var component2 = React.createClass({
displayName: 'component2',
tbValueChanged: function(e) {
this.props.settingsChanged(e.target.value);
},
render: function () {
console.log('component2.render');
return (
React.createElement('div', null,
React.createElement('div', null, 'component2'),
React.createElement('input', { value: this.props.settings.value, onChange: this.tbValueChanged })
)
);
}
})
In the console I see this:
component1.render app.js:27
component2.render app.js:42
app.settingsChanged app.js:5
component1.render app.js:27
component2.render app.js:42
http://jsfiddle.net/67m0z3ts/1/
Actually what's happening is a normal behaviour, once there is something changed in the main component, all components in that main one will be rendered again.
BUT the good news that you can change this default behaviour using shouldComponentUpdate(), which is true by default. Look at react.js documentation in advanced performance.
I hope that helps.
Good Luck
You can prevent React rendering with method shouldComponentUpdate.
So you have to add a these lines of code to your component1:
getInitialState : function(){
return {
shouldUpdate: true
}
},
shouldComponentUpdate: function(nextProps, nextState){
return nextState === this.state.shouldUpdate
},
And also Fiddle Link
I hope it will help you!
Thanks
I don't want to get into detail here, but in addition to other replies, you can try to enable the PureRenderMixin from React. From the docs:
Under the hood, the mixin implements shouldComponentUpdate, in which it compares the current props and state with the next ones and returns false if the equalities pass.
Related
I know you can pass down states and props in React from a parent component to a child component, but is there any way to do this the opposite way?
For example:
Given some child component:
var Child = React.createClass({
getInitialState: function(){
return {
data: ''
};
},
componentDidMount: function(){
this.setState({data: 'something'});
},
render: function() {
return (
<div>
...
</div>
);
}
});
and given some parent component:
var Parent = React.createClass({
render: function() {
return (
<div>
<Child />
...
</div>
);
}
});
Is there any way for me to give Parent the value of the state data from Child?
No.
But yes. But really no.
You cannot "pass" anything from a child to a parent in React. However, there are two solutions you can use to simulate such a passing.
1) pass a callback from the parent to the child
var Parent = React.createClass({
getInitialState: function() {
return {
names: []
};
},
addName: function(name) {
this.setState({
names: this.state.names.push(name)
});
},
render: function() {
return (
<Child
addName={this.addName}
/>
);
}
});
var Child = React.createClass({
props: {
addName: React.PropTypes.func.isRequired
},
handleAddName: function(event) {
// This is a mock
event.preventDefault();
var name = event.target.value;
this.props.addName(name);
},
render: function() {
return (
...
onClick={this.handleAddName}
...
);
}
});
The second option is to have a top-level state by using a Flux-style action/store system, such as Reflux or Redux. These basically do the same thing as the above, but are more abstract and make doing so on much larger applications very easy.
One way to do this is through a 'render props' pattern I was recently introduced to. Remember, this.props.children is really just a way for React to pass things down to a component.
For your example:
var Parent = React.createClass({
render: function() {
return (
<div>
<Child>
{(childState) => {
// render other 'grandchildren' here
}}
</Child>
</div>
);
}
});
And then in <Child> render method:
var Child = React.createClass({
propTypes: {
children: React.PropTypes.func.isRequired
},
// etc
render () {
return this.props.children(this.state);
}
});
This is probably best suited for cases where the <Child /> is responsible for doing something but doesn't really care much at all about the children that would be rendered in its place. The example the react training guys used was for a component that would fetch from Github APIs, but allow the parent to really control what / if anything was rendered with those results.
I am pretty new to react, trying to make some components work. I have
ObjectA:React.createClass({
propTypes: {
...
},
getInitialState: function() {
return {
myState: null
}
},
updateMyState: function(value) {
this.setState({
myState: value
})
}
render: function() {
return (<div className="my-class">'hello' +{this.state.myState}</div>);
}
});
ObjectB:React.createClass({
propTypes: {
...
},
render: function() {
return (<div className="my-class"><ObjectA / >
</div>);
}
});
I'd like to update ObjectA's state from ObjectB. How could I in ObjectB call ObjectA's updateMyState method?
Thanks!
The basic idea of React is the unidirectional data flow. That means that data is only shared downwards from an ancestor component to its children via the child's properties. We leave Flux like architectures and event emitters out of the equation for this simple example as it's not necessary at all.
The ONLY way then to change a component's state from the outside is changing the props it receives in the parent's render method. so myState would actually live in ObjectB and be given to ObjectA as property. In your example that would look like this:
ObjectA:React.createClass({
propTypes: {
...
},
render: function() {
return (<div className="my-class">'hello' +{ this.props.name }</div>);
}
});
ObjectB:React.createClass({
propTypes: {
...
},
getInitialState: function() {
return {
name: null
}
},
onNameChange: function(newName) {
this.setState({ name: newName })
},
render: function() {
return (
<div className="my-class">
<ObjectA name={ this.state.name } />
</div>
);
}
});
Is it possible in react to do something like this:
var App = React.createClass({
getInitialState: function(){
return {
children: [<div/>, <div/>],
comp: ''
};
},
componentWillMount: function(){
this.setState({
comp: <SomeComponent children={this.state.children}/>
});
},
render: function(){
return (
<div>
{this.state.comp === '' ? this.state.children : this.state.comp}
</div>
);
}
});
When I try to do something similar to this I get: Uncaught TypeError: Cannot read property '_currentElement' of null so I assume the answer is no, but I figure there has to be some way considering
<SomeComponent>
<div/>
</SomeComponet>
where <SomeCompent/> renders a <div/>, is valid. However in this particular case I get the same error doing that, but if you look at something like React-Bootstrap https://react-bootstrap.github.io/, it has to be possible.
Why do you want to pass html tags as state? I'm not saying is bad, but there's always a better solution to what you asking. Let's say a child component passing a state Boolean true or false to parent component( Flux - Action by child component pass to store, parent components can pick up the state with onChange event). With that you could invoke the parent element to render different view.
_onChange: function() {
this.setState(this._getStateFromStores());
},
render: function() {
var view;
if (this.state.childAction) {
view = <SomethingTrue/> ;
}
if (!this.state.childAction) {
view = <SomethingFalse/> ;
}
return (
<div>
{view}
</div>
);
I have the next component 'Father' that contains a 'Children' component in React js.
var Father = React.createClass({
render: function () {
return (
<div>
<Children/>
</div>
);
},
onUpdate: function(state) {
this.setState(state);
} });
I want to call the onUpdate function on the father from the children BUT without calling the 'Children' method 'componentDidUpdate' because I'm using that method for some other thing that breaks my application.
How can I do that?
Pass it down in properties. If you need to update only specific parts and prevent your children from updating, use the method shouldComponentUpdate
var Father = React.createClass({
render: function () {
return (
<div>
<Children onUpdateCallback={this.onUpdate}/>
</div>
);
},
onUpdate: function(state) {
this.setState(state);
}
});
var Child = React.createClass({
render: function () { ... },
shouldComponentUpdate: function (prevProps, prevState) { ... return false}
});
If your Children can't/shouldn't update while the Parent does, I think you are probably doing something wrong, but good luck.
Since React doesn't have any builtin way to manage document.title, I used to set it inside componentDidMount of my route handlers.
However now I need to amend the title based on state fetched asynchronously. I started putting assingments into componentDidUpdate, but every now and then I forget to put document.title assignment into some pages, and previous title sticks around until I finally notice it.
Ideally I'd like a way to express document.title declaratively, without having to assign it. Some kind of “fake” component would probably be most convenient, given that I want to be able to specify the document title at several nesting levels:
On top level (the default title);
On page level (for some of the pages, but not all);
Sometimes, on inner component level (e.g. user typing into a field).
Additional requirements:
Title specified in child should override title specified by parent;
Reliable (guarantees cleanup on route change);
Should not emit any DOM (i.e. no hacks with component returning <noscript>);
I'm using react-router but it's better if this component works with other routers too.
Anything I can use?
I wrote react-document-title just for that.
It provides a declarative way to specify document.title in a single-page app.
If you want to get title on server after rendering components to string, call DocumentTitle.rewind().
Features
Does not emit DOM, not even a <noscript>;
Like a normal React compoment, can use its parent's props and state;
Can be defined in many places throughout the application;
Supports arbitrary levels of nesting, so you can define app-wide and page-specific titles;
Works on client and server.
Example
Assuming you use something like react-router:
var App = React.createClass({
render: function () {
// Use "My Web App" if no child overrides this
return (
<DocumentTitle title='My Web App'>
<this.props.activeRouteHandler />
</DocumentTitle>
);
}
});
var HomePage = React.createClass({
render: function () {
// Use "Home" while this component is mounted
return (
<DocumentTitle title='Home'>
<h1>Home, sweet home.</h1>
</DocumentTitle>
);
}
});
var NewArticlePage = React.createClass({
mixins: [LinkStateMixin],
render: function () {
// Update using value from state while this component is mounted
return (
<DocumentTitle title={this.state.title || 'Untitled'}>
<div>
<h1>New Article</h1>
<input valueLink={this.linkState('title')} />
</div>
</DocumentTitle>
);
}
});
Source
I keep track of mounted instances and only use title given to the top DocumentTitle in the mounted instance stack whenever it updates, gets mounted or unmounted. On server, componentWillMount fires but we won't get didMount or willUnmount, so we introduce DocumentTitle.rewind() that returns a string and destroys state to prepare for next request.
var DocumentTitle = React.createClass({
propTypes: {
title: PropTypes.string
},
statics: {
mountedInstances: [],
rewind: function () {
var activeInstance = DocumentTitle.getActiveInstance();
DocumentTitle.mountedInstances.splice(0);
if (activeInstance) {
return activeInstance.props.title;
}
},
getActiveInstance: function () {
var length = DocumentTitle.mountedInstances.length;
if (length > 0) {
return DocumentTitle.mountedInstances[length - 1];
}
},
updateDocumentTitle: function () {
if (typeof document === 'undefined') {
return;
}
var activeInstance = DocumentTitle.getActiveInstance();
if (activeInstance) {
document.title = activeInstance.props.title;
}
}
},
getDefaultProps: function () {
return {
title: ''
};
},
isActive: function () {
return this === DocumentTitle.getActiveInstance();
},
componentWillMount: function () {
DocumentTitle.mountedInstances.push(this);
DocumentTitle.updateDocumentTitle();
},
componentDidUpdate: function (prevProps) {
if (this.isActive() && prevProps.title !== this.props.title) {
DocumentTitle.updateDocumentTitle();
}
},
componentWillUnmount: function () {
var index = DocumentTitle.mountedInstances.indexOf(this);
DocumentTitle.mountedInstances.splice(index, 1);
DocumentTitle.updateDocumentTitle();
},
render: function () {
if (this.props.children) {
return Children.only(this.props.children);
} else {
return null;
}
}
});
module.exports = DocumentTitle;
Take a look at the NFL's react-helmet.
class Layout extends React.Component {
constructor(props){
super(props);
document.title = this.props.title;
}
render(){
return(
<div>
</div>
);
}
}
and then <Layout title="My Title"/> that easy!
Try react-frozenhead, it's actually more sophisticated than react-document-title - it allows us change title, description and anything else in section.
Meanwhile, 3 years have gone! ;-)
If you want to manipulate other page headers than title (like description, canonical, etc.), react-document-meta NPM dependency could be a good thing to use.