Render Only Child Component Only On Prop Change - javascript

I want to re-render my child component without re-rendering the parent component when the parent's state changes.
In this example, componentWillReceiveProps is never called.
Thank You!
Parent Component
export default class Parent extends Component {
constructor(props) {
super(props);
this.state = {
myValue: 'hello'
}
}
shouldComponentUpdate(nextProps, nextState) {
return false;
}
myFunction() {
this.setState(prevState => {
return {myValue: 'world'};
});
}
render() {
return (
<View>
<Button onPress={myFunction} title="Learn More"/>
<Child myText={this.state.myValue}/>
</View>
);
}
}
Child Component
export default class Child extends Component {
constructor(props) {
super(props);
}
componentWillReceiveProps(nextProps) {
console.log('This Is Never Called');
}
render() {
return (
<View>
<Text>{this.props.myText}</Text>
</View>
);
}
}

There is no way to do what you are proposing explicitly. When you define:
shouldComponentUpdate(nextProps, nextState) {
return false;
}
are telling Parent never to rerender after its initial render. However the passing of props to Child (and therefore the impetus for Child to rerender) happens inside the render method of Parent. So when you block rerending on Parent you are also blocking rerendering on all children of Parent.
There is, however, no need to block rerendering on Parent because React will modify the DOM as little as possible, so you will only see changes in parts of parent that need to be modified (due to a change of state). As long as all the props being passed to the other children of Parent (other than Child that is) remain unchanged, only Child will be modified in a Parent.render call.
Basically React already handles what you are trying to do.

In order to re-render child component with new props, parent component has to be re-rendered. There are generally no reasons to not re-render parent component in this situation. React was designed to do this efficiently and reuse existing DOM elements on re-render where possible.
The alternative approach is to make child component re-render its children and make parent component trigger the update somehow. This can be done with refs, for instance:
export default class Parent extends Component {
state = {
myValue: 'hello'
}
childRef = React.createRef();
myFunction = () => {
this.childRef.current.setText('world');
}
render() {
return (
<View>
<Button onPress={this.myFunction} title="Learn More"/>
<Child ref={this.childRef} myText={this.state.myValue}/>
</View>
);
}
}
And child component maintains its own state:
export default class Child extends Component {
static getDerivedStateFromProps({ myText }, state) {
return {myText, ...state};
}
setText(myText) {
this.setState({ myText });
}
render() {
return (
<View>
<Text>{this.state.myText}</Text>
</View>
);
}
}
Here's a demo.
This is acceptable solution but it results in less straightforward design. 'Dumb' Child like in original code is a preferable way to do this which shouldn't be changed for optimization reasons in general. If there are problems with re-rendering Parent children, they possibly should be addressed in another way.

Related

Passing props down to child inside parent's constructor

I am trying to pass a parent's state down into a grandchild's props. The thing is, I am creating the grandchild component in the child's constructor/state variable, and it doesn't seem to want to pass the props down. The child successfully receives the props results object, but the grandchild has an empty object when I reference this.props.results. How can I send the props down to the grandchild?
Parent Component
render()
{
return( <ChildComponent results={this.state.results}/> );
}
Child Component
constructor(props) {
super(props);
this.state = {
containerContent: [
<GrandChildComponent results={props.results}/>, //this.props.results also does not work
]
}
}
render()
{
<main>
{this.state.containerContent[0]}
</main>
}
Grandchild Component
render()
{
<h3>{this.props.results.someValue}</h3> //Throws an error, saying `results` is empty.
}
You can use context api or else use redux.
which is more convenient.

React props value is undefined

This is my parent code:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
tags: [],
};
}
componentDidMount() {
this.getTags();
}
getTags() {
//method gets tags from the backend
}
render() {
return <Child tags={this.state.tags} />;
}
}
And this is basically my child component:
export default class Child extends Component {
constructor(props) {
super(props);
this.state = {
tags: props.tags,
};
}
componentWillReceiveProps(nextProps) {
this.setState({
tags: nextProps.tags,
});
}
}
But when I console log tags somewhere in the Child component, it is undefined. Maybe it is undefined because the child component gets rendered before the parent component calls the method getTags? Or is there any other problem with this code? And how can I avoid this problem that tags are undefined in the child component?
Cheers
To avoid your problem, you shouldn't be rendering your Child component until the this.state.tags has any useful values.
Here is how you can do it and also show a "Loading..." text, so the user isn't worried the page is broken.
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
tags: [],
};
}
componentDidMount() {
this.getTags();
}
getTags() {
//method gets tags from the backend
}
render() {
return this.state.tags.length ? (
'Loading...'
) : (
<Child tags={this.state.tags} />
);
}
}
Your child component will definitely get rendered with the empty 'tags' array as a prop. Then, when getTags() returns the data, the newly populated tags array will be passed to the child as a prop, forcing the child to get re-rendered with the new data.
It should be the empty array though, not "undefined". You might check your getTags() method and the API you are calling to make sure you aren't getting "undefined" from there.
componentWillReceiveProps is legacy and should not be used. See the following link in the React docs for details: https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops
That documentation will walk you through what to do if you need to perform side effects as a result of changing props.
Right now the only thing is componentWillReceiveProps is to set local state to the props, which is totally superfluous. Is there something else you are needing to do there?

Child component doesn't get changed prop

I have the following structure:
class Parent extends React.Component {
componentDidMount() {
document.addEventListener('keydown', () => {
this.value++;
})
}
this.value = 0;
render() {
return (<ChildComponent value={this.value} />)
ChildComponent simply renders the value:
class ChildComponent extends Component {
render() {
return (
<div>
{this.props.value}
</div>
);
}}
I don't want to rerender Parent component on every KeyDown event, that's why I don't put a value to the state.
I want ChildComponent rerenders on every KeyDown event, but ChildComponent renders only once because it doesn't get changed value and always shows 0 although this.value is changing.
Is it possible to rerender ChildComponent while changing this.value of the ParentComponent or I should place logic into ChildComponent using setState to render correct result?
You should add the value to parent state. This is simply the way React works. Even if you could manually trigger a rerender on the child component, it would still be 0 as still 0 is provided props. When React detects state has changed on Parent component, it will calculate the virtual dom of all child elements, do a diff on the virtual dom vs the real dom, then selectively update the real dom with those values (only the inner text of the Child component div will actually be new). React is incredibly optimised to handle rerendering using the virtual dom, and you should not worry about performance loss of this situation.
The reason the child component didn’t get called when value changes because you are overriding normal variable value but not react component state. So inorder to call child component when value changes you need to manage value property in component state of parent so whenever you modify it’s value using setState, component will re render
Change
class Parent extends React.Component {
componentDidMount() {
document.addEventListener('keydown', () => {
this.value++;
})
}
this.value = 0;
render() {
return (<ChildComponent value={this.value} />)
}
}
To
class Parent extends React.Component {
constructor(props){
super(props);
this.state = {
value: 0
}
}
componentDidMount() {
document.addEventListener('keydown', () => {
this.setState({value: this.state.value++});
})
}
render() {
return (<ChildComponent value={this.state.value} />)
}
}

Can we pass setState as props from one component to other and change parent state from child component in React?

class App extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
this.setState=this.setState.bind(this)
}
render() {
return (
<div>
<Hello name={this.state.name} />
<p>
Start editing to see some magic happen :)
</p>
<Child {...this}/>
</div>
);
}
}
child Component
var Child=(self)=>{
return(
<button onClick={()=>{
self .setState({
name:"viswa"
})
}}>Click </button>
)
here I am binding the setState function and send this as props to child component.This will change state of parent from child.Is this proper way?
But this is simple than passing function.If I want change many state change. this will be simple and faster way compare to passing function right ?
The correct way to do this is as simple as yours and does not violate best practices:
class App extends Component {
state = {
name: 'React',
};
render() {
return (
<div>
<Hello name={this.state.name} />
<p>
Start editing to see some magic happen :)
</p>
<Child onClick={() => this.setState({name: 'viswa'})}/>
</div>
);
}
}
const Child=({onClick})=>(
<button onClick={onClick}>Click</button>
);
You shouldn't pass the setState directly, as the setState function will not change the state immediately.
as the documents said:
Think of setState() as a request rather than an immediate command to
update the component. For better perceived performance, React may
delay it, and then update several components in a single pass. React
does not guarantee that the state changes are applied immediately.
setState() does not always immediately update the component. It may batch or defer the update until later. So you'd better to manage the calling of setState function together as there may have competing of mutating parent's state. It is not recommended to pass this function to another component.
Encapsulating the calling of setState function in one class makes your code stronger.
As #yBrodsky said, you should rather pass down a function which does mutate the state. Here is an example:
class App extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
this.update=this.update.bind(this);
}
update(nextState) {
this.setState(nextState);
}
render() {
return (
<Child updateParent={this.update} />
);
}
}
const Child = ({updateParent}) => (
<button onClick={() => updateParent({name: 'Foo bar'})}>Click</button>
);
You now have full control over the state of the Parent in the child. Just pass the object to be shallowly merged into the parent state. In this example, name in App will change to Foo bar on button click.
i guess in functional components its possible to send your setState to childrens and change parent state in them but not in class base components

Letting a child know that it should update its state in React

I'm trying to let a child Component know that it should update its state after a prop change in the parent.
There is no state that needs to be shared between the two. The only thing that needs to happen is that the parent should somehow let the child know that it needs to update its state (literally call setState by itself with the info it already has).
So far I can only figure out to do in the "React"-way through the componentWillReceiveProps and sending some arbitrary props, like a number, to let the child know that it should call the function to set the state.
Another way would be to use signals to let the child know, but this seems a bit over the top for this situation.
So in summary:
The parent needs to let the child know that it should call a function
The function will update the state (setState) of the child
There is no need for the child to receive any information from the parent
Can anyone help me figure out the best way to do this?
As you can see in the snippet, this is more or less the situation. I would like to know the best way to have the Child component call the _updateState function when the Parents props have changed (does not happen in the snippet right now).
//Imagine this is the redux-container that passes the store state to the parent.
class ParentWrapper extends React.Component {
constructor(){
super();
this.state = {status: 'normal'};
}
//This would be an action to the reducer that would update the store state
_updateStatus(){
this.setState({status: 'updated'});
}
render(){
return (
<div>
<button onClick={this._updateStatus.bind(this)}>Click me</button>
<Parent status={this.state.status} />
</div>
);
}
}
class Parent extends React.Component {
render(){
return (
<div>
<Child />
</div>
);
}
}
Parent.propTypes = {
status: React.PropTypes.string
};
Parent.defaultProps = {
status: 'normal'
};
class Child extends React.Component {
constructor(){
super();
this.state = { test: 1 };
}
_updateState(){
this.setState({test: this.state.test + 1});
}
render(){
return (
<div>Child: {this.state.test}</div>
);
}
}
ReactDOM.render(<ParentWrapper />, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react-dom.min.js"></script>
<div id="container"></div>
EDIT: added snippet.
You can use refs to access all the methods under the child component.
See the following fiddle
https://jsfiddle.net/pranesh_ravi/412j5ucw/
Here using refs, I'm calling a function inside the child which will change the state of the child component.

Categories

Resources