reactjs更新父级然后更新兄弟姐妹

时间:2016-12-17 20:39:31

标签: reactjs

我正在使用http://andrewhfarmer.com/component-communication/#3-callback-functions中的示例来传达从孩子到父母的信息。

我正在尝试用reactjs创建一个星级评分系统。在重新渲染时,它不会更新兄弟姐妹的状态。我在调用this.forceUpdate()时尝试调用this.render()StarsContainer.onRate(),唉这也无法解决问题。

Expected output:
StarContainer render: 5 <-
RATING: 5
Star render: 0 : 5
Star render: 1 : 5
Star render: 2 : 5
Star render: 3 : 5
Star render: 4 : 5
Star render: 5 : 5
Star render: 6 : 5

Actual output:
StarContainer render: 5 <-
RATING: 5
Star render: 0 : 1
Star render: 1 : 1
Star render: 2 : 1
Star render: 3 : 1
Star render: 4 : 1
Star render: 5 : 5
Star render: 6 : 1

调试清楚地显示父StarContainer正在重新呈现,并且该组件的状态的评级为5.它还显示正在重新呈现Star组件。但是,“兄弟姐妹”的评级没有更新。

我是否发现了错误,或者这是预期的行为?

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>
    <script src="https://unpkg.com/react@latest/dist/react.js"></script>
    <script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <style>
        a.star:hover {
            cursor: pointer;
            color: red;
        }
        a.star {
            font-size: 2em;
        }
    </style>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">

        class Star extends React.Component {
            constructor(props) {
                super(props);
                this.state = {
                    rating: props.rating,
                    value: props.value,
                    onValue: props.onValue,
                    offValue: props.offValue,
                    className: props.className,
                    onRate: props.onRate
                };
            }

            handleClick(e) {
                e.preventDefault();
                console.log('The link was clicked.');
                this.setState({rating: this.state.value});
                console.log("this.state.value:",this.state.value);
                this.props.onRate(this.state.value);
            }

            render() {
                var rating = this.state.rating;
                var value = this.state.value;
                console.log("Star render:", value, ":",rating);

                if (rating >= value) {
                    return(<a className={this.state.className} onClick={(e) => this.handleClick(e)}>{this.state.onValue}</a>);
                } else {
                    return(<a className={this.state.className} onClick={(e) => this.handleClick(e)}>{this.state.offValue}</a>);
                }
            }
        }

        Star.propTypes = {
          onRate: React.PropTypes.func,
        };

        class StarsContainer extends React.Component {
            constructor(props) {
                super(props);

                this.state = {
                    rating: props.rating,
                    className: props.className
                };
            }
            onRate(newRating) {
                console.log("StarsContainer onRate:", newRating);
                this.setState({rating: newRating});
                console.log("New Rating:", this.state.rating);
            }
            render() {
                console.log("StarContainer render:", this.state.rating, "<-");
                const rating = this.state.rating;
                console.log("RATING:", rating);
                return(<span>
                    <Star rating={rating} value="0" onValue="0" offValue=" " className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="1" onValue="+" offValue="-" className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="2" onValue="+" offValue="-" className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="3" onValue="+" offValue="-" className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="4" onValue="+" offValue="-" className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="5" onValue="+" offValue="-" className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="6" onValue="?" offValue="" className="star" onRate={this.onRate.bind(this)} />
                </span>);
            }
        }

        StarsContainer.propTypes = {
          onRate: React.PropTypes.func,
        };

        ReactDOM.render(
          <StarsContainer rating="1" onValue="+" offValue="-" className="star" />,
          document.getElementById('root')
        );

    </script>
  </body>
</html>

1 个答案:

答案 0 :(得分:0)

您无需在案例中保留Star(子)组件的内部状态。只需要保持StarsContainer(父级)的内部状态,并将其作为对子进程的回调传递给它。

在您的情况下,您只在构造函数中将 this.props.rating 分配给 this.state.rating ,这就是每次组件重新启动时的原因渲染,但没有改变。

我根据您的代码做了一个快速摘录。其中大部分已移除<Star />组件中的 this.state.rating ,其余部分已移除<StarContainer />的一些道具。

如果您对[{1}}和this.state更加熟悉,那么您将会发现为什么它被称为 React JS。

this.props
        class Star extends React.Component {
            constructor(props) {
                super(props);
                this.state = {
                    onValue: props.onValue,
                    offValue: props.offValue,
                    className: props.className,
                    onRate: props.onRate
                };
            }

            handleClick(e) {
                e.preventDefault();
                console.log('The link was clicked.');
                console.log("this.state.value:",this.props.value);
                this.props.onRate(this.props.value);
            }

            render() {
                var rating = this.props.rating;
                var value = this.props.value;
                console.log("Star render:", value, ":",rating);

                if (rating >= value) {
                    return(<a className={this.state.className} onClick={(e) => this.handleClick(e)}>{this.state.onValue}</a>);
                } else {
                    return(<a className={this.state.className} onClick={(e) => this.handleClick(e)}>{this.state.offValue}</a>);
                }
            }
        }

        Star.propTypes = {
          onRate: React.PropTypes.func,
        };

        class StarsContainer extends React.Component {
            constructor(props) {
                super(props);

                this.state = {
                    rating: 0,
                    className: props.className
                };
            }
            onRate(newRating) {
                console.log("StarsContainer onRate:", newRating);
                this.setState({rating: newRating});
                console.log("New Rating:", this.state.rating);
            }
            render() {
                console.log("StarContainer render:", this.state.rating, "<-");
                const rating = this.state.rating;
                console.log("RATING:", rating);
                return(<span>
                    <Star rating={rating} value="0" onValue="0" offValue=" " className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="1" onValue="+" offValue="-" className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="2" onValue="+" offValue="-" className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="3" onValue="+" offValue="-" className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="4" onValue="+" offValue="-" className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="5" onValue="+" offValue="-" className="star" onRate={this.onRate.bind(this)} />
                    <Star rating={rating} value="6" onValue="?" offValue="" className="star" onRate={this.onRate.bind(this)} />
                </span>);
            }
        }

        StarsContainer.propTypes = {
          onRate: React.PropTypes.func,
        };

        ReactDOM.render(
          <StarsContainer onValue="+" offValue="-" className="star" />,
          document.getElementById('root')
        );