How can I call forceUpdate on the root element in React? - reactjs

I need to call forceUpdate on the app root of my React App or on another component than the one I am currently in. I know to call forceUpdate on the current component it is this.forceUpdate(), but how would I call it on another component?

You can pass the this.forceUpdate() function vis props to a child component
root.js
var Root = React.createClass({
render: function() {
return (
<UpdateComponent
rootUpdate={this.forceUpdate.bind(this)}
/>
);
}
});
Then you can access call this.props.rootUpdate() in your UpdateComponent whenever you need the root to be force updated.

forceUpdate is a worse case scenario and should be avoided because it deviates from the React way of doing things.
Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render(). This makes your component "pure" and your application much simpler and more efficient.
Changing the key of the element you want re-rendered will work. Set the key prop on your element via state and then when you want to update set state to have a new key.
<Element key={this.state.key} />
Then a change occurs and you reset the key
this.setState({ key: Math.random() });
I want to note that this will replace the element that the key is changing on. It is always discourage to use the forceUpdate as there is always a way to avaoid this.

Related

Force update all the components in React#16.8.6

I want to update all the components in my React application (no matter what is the nesting level or if there is any prop or state change).
I tried using this.forceUpdate() but as some of the components don't use any props or state, those and their children are not updating.
Also, I tried the solution mentioned in the example but this also didn't work.
App.js
render() {
return (
<div>
<Routes />
</div>
);
}
As you can see, Routes don't take any props, so this component is not re-rendering. As a result of which, none of the components inside Routes is updating.
One way is using the store. As this is a small operation only, so I don't want to use the store for this kind of use case.
If you really need to update components on every render, you can use a key prop that's different every time the component renders. This will force React to unmount the previous instance of component and mount the new one with all the state and props being reset. In case of Route the easiest is to assign key as the current page url:
render() {
return (
<div>
<Routes key={window.location.href} />
</div>
);
}
With other components it's a bit more tricky, since you'll need to manually ensure the key is different each time.
If you would like to have more granular control over when the components are updated, you can hook the key prop to the state and change it onClick.
This post explains the approach in more detail.

`componentWillReceiveProps` explanation

I recently wanted to upgrade my knowledge of React, so I started from the component lifecycle methods. The first thing that got me curious, is this componentWillReceiveProps. So, the docs are saying that it's fired when component is receiving new (not necessarily updated) props. Inside that method we can compare them and save into the state if needed.
My question is: Why do we need that method, if changes in props of that component (inside parent render) will trigger the re-render of this child component?
One common use case are state (this.state) updates that may be necessary in response to the updated props.
Since you should not try to update the component's state via this.setState() in the render function, this needs to happen in componentWillReceiveProps.
Additionally, if some prop is used as a parameter to some fetch function you should watch this prop in componentWillReceiveProps to re-fetch data using the new parameter.
Usually componentDidMount is used as a place where you trigger a method to fetch some data. But if your container, for example, UserData is not unmounted and you change userId prop, the container needs to fetch data of a user for corresponding userId.
class UserData extends Component {
componentDidMount() {
this.props.getUser(this.props.userId);
}
componentWillReceiveProps(nextProps) {
if (this.props.userId !== nextProps.userid) {
this.props.getUser(nextProps.userId);
}
}
render() {
if (this.props.loading) {
return <div>Loading...</div>
}
return <div>{this.user.firstName}</div>
}
}
It is not a full working example. Let's imagine that getUser dispatch Redux action and Redux assign to the component user, loading and getUser props.
It 'serves' as an opportunity to react to the incoming props to set the state of your application before render. If your call setState after render you will re-render infinitely and that's why you're not allowed to do that, so you can use componentWillReceiveProps instead.
But... you are beyond CORRECT in your confusion, so correct in fact that they are deprecating it and other Will-lifecycle hooks Discussion Deprecation.
There are other ways to accomplish what you want to do without most of those Will-lifecycle methods, one way being don't call setState after render, just use the new incoming props directly in render (or wherever) to create the stateful value you need and then just use the new value directly, you can then later set state to keep a reference for the next iteration ex: this.state.someState = someValue, this will accomplish everything and not re-render the component in an infinite loop.
Use this as an opportunity to react to a prop transition before render() is called by updating the state using this.setState(). The old props can be accessed via this.props. Calling this.setState() within this function will not trigger an additional render.
Look at this article
the componentWillReceiveProps will always receive as param "NxtProps", componentWillReceiveProps is called after render().
some people use this method use this to compare nxtProps and this.props to check, if something should happen before the component call render, and to some validations.
check the react's documentation to know more about react lifecycle!
hope this could help you!
changes in props of that component (inside parent render) will trigger the re-render of this child component
You are absolutely right. You only need to use this method if you need to react to those changes. For instance, you might have a piece of state in a child component that is calculated using multiple props.
Small Example:
class Test extends Component {
state = {
modified: "blank"
};
componentDidMount(){
this.setState({
modified: `${this.props.myProp} isModified`
});
}
componentWillReceiveProps(nextProps) {
this.setState({
modified: `${nextProps.myProp} isModified`
});
}
render() {
return <div className="displayed">{this.state.modified}</div>
}
}
In this example, componentDidMount sets the state using this.props. When this component receives new props, without componentWillReceiveProps, this.state.modified would never be updated again.
Of course, you could just do {this.props.myProp + "IsModified"} in the render method, but componentWillReceiveProps is useful when you need to update this.state on prop changes.

React: Losing ref values

I am using two components and I am using this pattern: child component should stay isolated as much it can - it is handling its own validation error. Parent component should check for errors which have dependencies between children. So, in my case: password field and password confirmation field.
Here is my code:
a) SignUp (parent)
Setting initial state.
constructor() {
super();
this.state = {
isPasswordMatching: false
};
}
In render() method I am outputting my child component. Through prop called callback I am propagating method isPasswordMatching() by binding parent's this. The goal is that method can be called within child component.
<TextInput
id={'password'}
ref={(ref) => this.password = ref}
callback={this.isPasswordMatching.bind(this)}
// some other unimportant props
/>
<TextInput
id={'passwordConfirm'}
ref={(ref) => this.passwordConfirm = ref}
...
isPasswordMatching() method is checking if passwords match (through refs this.password and this.passwordConfirm) and then updates state. Please note that this method is called inside child (password or passwordConfirm).
isPasswordMatching() {
this.setState({
isPasswordMatching: this.password.state.value === this.passwordConfirm.state.value
});
}
b) TextInput (child)
Setting initial state.
constructor() {
super();
this.state = {
value: '',
isValid: false
};
}
On blur validation is done and state is updated.
onBlur(event) {
// doing validation and preparing error messages
this.setState({
value: value,
isValid: this.error === null
});
}
Latest. Callback prop is called.
componentDidUpdate(prevProps) {
if (prevProps.id === 'password' || prevProps.id === 'passwordConfirm') {
prevProps.callback();
}
}
Issue
Somehow my refs are lost. Scenario:
Parent component is renderder
Child components are rendered
I am entering one of input fields and get out (this invokes onBlur() method) - state gets updated, child component is rendered
componentDidUpdate() is invoked and prevProp.callback() as well
When going to isPasswordMatching() method I am outputting this.password and this.passwordConfirm - they are objects with expected values of reference. Updating state of parent - component gets rendered.
Then again all children are rendered, components get updated, callback is called but this time this.password and this.passwordConfirm are null.
I have no idea why references are kinda lost. Should I be doing something differently?
Thank you in advance.
See the react documentation here, with important warnings and advise about when to use or not to use refs.
Note that when the referenced component is unmounted and whenever the ref changes, the old ref will be called with null as an argument. This prevents memory leaks in the case that the instance is stored, as in the second example. Also note that when writing refs with inline function expressions as in the examples here, React sees a different function object each time so on every update, ref will be called with null immediately before it's called with the component instance.
I'm not sure if this answers #be-codified's question for not, but I found this running into a similar issue. In my case, it turned out that it was due to using a functional component.
https://reactjs.org/docs/refs-and-the-dom.html#refs-and-functional-components
Refs and Functional Components
You may not use the ref attribute on functional components because they don’t
You should convert the component to a class if you need a ref to it, just like you do when you need lifecycle methods or state.
You can, however, use the ref attribute inside a functional component as long as you refer to a DOM element or a class component
The documentation explains what you should do to solve the issue if you have control of the component you're trying to render.
However in my case, the component was from a 3rd party library. So, simply wrapping the component worked fine.
Working
<div ref={element => this.elementName = element}>
<FunctionalComponent />
</div>
Not Working
sets this.elementName to null
<FunctionalComponent ref={element => this.elementName = element} />
Hope this helps anyone finding this question like I did.

React reusable stateful component

Let's say I created a component which can be turned on/off based on state.
var onOff = React.createElement(<OnOff />, mountElement);
onOff.setState({ on: false });
Later I'm creating a new component called Parent, which will use OnOff inside it.
render() { return <div><OnOff /></div> }
Now how can I change the OnOff state? There is no way I can call setState on it. And I should not according to React doc. So I have to add initial state to OnOff's props:
constructor(props) {
super(props);
this.state = { on: props.initialOn };
}
then in Parent's render method, set the initialOn prop with its state:
render() { return <div><OnOff initialOn={false} /></div> }
But it's still not working, because whenever I change Parent's state, the OnOff component inside it is not re-created with new initial state. Instead, it is only re-rendered with old state. I have a CodePen to prove it: http://codepen.io/anon/pen/QjMwjO?editors=101
You can update the state of the OnOff component by declaring the update also inside a componentWillReceiveProps function, something like:
componentWillReceiveProps:
function(nextProps) {
this.setState({
on : nextProps.initialOn
});
}
This allows you to update state, when new props arrive. And it is valid react.
You should however consider if you need state in OnOff at all: if the only initial setting and all updates ONLY come from its parent component, then a stateless component would be better.
One of the important things to understand when "Thinking in React" is to figure out which component does State belong to.
Read this in React docs
What Components Should Have State?
Most of your components should simply take some data from props and render it. However, sometimes you
need to respond to user input, a server request or the passage of
time. For this you use state.
Try to keep as many of your components as possible stateless. By doing
this you'll isolate the state to its most logical place and minimize
redundancy, making it easier to reason about your application.
A common pattern is to create several stateless components that just
render data, and have a stateful component above them in the hierarchy
that passes its state to its children via props. The stateful
component encapsulates all of the interaction logic, while the
stateless components take care of rendering data in a declarative way.
Thus, your OnOff should not have state but use properties passed down from the parent instead. I have illustrated this at http://codepen.io/anon/pen/gaxbGm?editors=101
render() {
writeLog("OnOff render called!")
writeLog("Child: " + this.props.initialOn)
return <span>{this.props.initialOn ? "On" : "Off"}</span>;
}
I would also recommend reading "Thinking in React" to get further clarity.

reactjs rendering with state or props

I would like to know difference between rendering component with state or props directly.
getInitialState:
data: this.props.data
Following code is for render function
1.
data = this.state.data
return (<Component data={data} />)
2.
return (<Component data={this.state.data} />)
3.
return (<Component data={this.props.data} />)
First two situations are crashing when I use setState on listening reflux action.
If anyone has recommendations to use other than setState or tell me the difference about those three code snippets would be very much appreciated.
Putting props in state like this:
getInitialState: function () {
return {
someKey: this.props.someKey
};
}
is an anti-pattern, unless you intend to modify the value of someKey later on and you use the prop as just an initial value.
So if you don't change the value of the prop passed in, you should go with number three.
The difference is that a component that doesn't have state can be considered "pure" (the same props passed in gives the same output, everytime) and those components are almost always easier to reason about. Duplicating the prop in state without mutating the state just gives you more lines of code in the component, and it might confuse someone else reading the code. It's a pure component disguised as an impure component.
A bit more about props and states. Props and state are related. The state of one component will often become the props of a child component. Props are passed to the child within the render method of the parent as the second argument to React.createElement() or, if you're using JSX, the more familiar tag attributes.
<MyChild name={this.state.childsName} />
The parent's state value of childsName becomes the child's this.props.name. From the child's perspective, the name prop is immutable. If it needs to be changed, the parent should just change its internal state:
this.setState({ childsName: 'New name' });
and React will propagate it to the child for you. A natural follow-on question is: what if the child needs to change its name prop? This is usually done through child events and parent callbacks. The child might expose an event called, for example, onNameChanged. The parent would then subscribe to the event by passing a callback handler.
<MyChild name={this.state.childsName} onNameChanged={this.handleName} />
The child would pass it's requested new name as an argument to the event callback by calling, e.g., this.props.onNameChanged('New name'), and the parent would use the name in the event handler to update its state.
handleName: function(newName) {
this.setState({ childsName: newName });
}

Resources