简体   繁体   中英

Rerendering React props.children

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 ?

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

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM