3

I have this kind of a setup:

// inside Parent.js class Parent extends React.Component { render() { return { this.props.children } } } // inside Child.js class Child extends React.Component { render() { let message; const greet = this.context.store.parentState.greet; if(greet) message = 'Hello, world!'; return ( <div> { message } </div> ) } } Child.contextTypes = { store: PropTypes.object.isRequired } // inside App.js <Parent> <Route path='/a-path' component={ Child } /> </Parent> 

When Parent receives new state through setState, its render method is called but the render method in Child is not called!

The reason I want to achieve that is because some logic in Child is dependent on the state of Parent.

If I pass the state of Parent via context like how the store is passed and then access it in Child via this.context.parentState, this seems to be working and causing a call on Child's render method, I guess it's because we're receiving new context.

Why is this? context is great but is there a good way around this particular issue without needing context?

2 Answers 2

3

If you are rendering components as children, which aren't components to Route, you can make use of React.cloneElement with React.Children.map like

// inside Parent.js class Parent extends React.Component { render() { return React.Children.map(this.props.children, (child) => React.cloneElement(child, {parentState: this.state.parentState}) ); } } 

However if elements rendered as Children to Parent are Routes then either you need to make use of context or write a wrapper around Route so that any extra props that the Route receives are passed on to the component

const RouteWrapper = ({exact, path, component: Component, anyOtherRouterProp, ...rest}) => <Route exact={exact} path={path} {...otherRouterProps} render={(props) => <Component {...props} {...rest} />} /> 

Where in the above case anyOtherRouterProp are the props that are applicable to the Route and needs to be destructured separately. After this you can make use of React.Children.map and React.cloneElement to pass on the props to children.

Although this is one such way, I would still recommend you to make use of context, specially with the introduction of new context API which makes it extremely easy to implement

Sign up to request clarification or add additional context in comments.

2 Comments

response much appreciated @Shubham Khatri. Quite an amount to learn here :). I think as you noted context is more appropriate for this issue. Besides that, is it exhaustive to assert that a component is re-rendered only on receiving new props, context, or state via setState??
Besides that, is it exhaustive to assert that a component is re-rendered only on receiving new props, context, or state via setState?? Not necessarily, because someone can just call forceUpdate to trigger a re-render, apart from that if the parent rerenders, all the children will also trigger their render method unless they are PureComponents
1

You can do like this....

 // inside Parent.js class Parent extends React.Component { render() { return ( <Child children={this.props.children} /> ) } } // inside Child.js class Child extends React.Component { render() { let message; const greet = this.context.store.parentState.greet; if(greet) message = 'Hello, world!'; return ( <div> { message } { this.props.children } </div> ) } } Child.contextTypes = { store: PropTypes.object.isRequired } // inside App.js <Parent> <Route path='/a-path' component={ Child } /> </Parent> 

2 Comments

thanks for the response. I want to avoid using Child inside of Parent because Parent can have more than just Child as children.
for that you can use redux or flux.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.