在React.js中触发子重新渲染

时间:2015-05-04 15:46:20

标签: javascript reactjs

Parent(我的示例中为MyList)组件通过Child(MyComponent)组件呈现数组。 Parent决定更改数组中的属性,React触发子重新渲染的方式是什么?

在调整数据后,我在Parent中想到的是this.setState({});。这是一种触发更新的黑客还是反应方式?

JS小提琴: https://jsfiddle.net/69z2wepo/7601/

var items = [
  {id: 1, highlighted: false, text: "item1"},
  {id: 2, highlighted: true, text: "item2"},
  {id: 3, highlighted: false, text: "item3"},
];

var MyComponent = React.createClass({
  render: function() {
    return <div className={this.props.highlighted ? 'light-it-up' : ''}>{this.props.text}</div>;
  }
});

var MyList = React.createClass({
  toggleHighlight: function() {
    this.props.items.forEach(function(v){
      v.highlighted = !v.highlighted;
    });

    // Children must re-render
    // IS THIS CORRECT?
    this.setState({});
  },

  render: function() {
    return <div>
      <button onClick={this.toggleHighlight}>Toggle highlight</button>
      {this.props.items.map(function(item) {
          return <MyComponent key={item.id} text={item.text} highlighted={item.highlighted}/>;
      })}
    </div>;
  }
});

React.render(<MyList items={items}/>, document.getElementById('container'));

5 个答案:

答案 0 :(得分:43)

这里的问题是您在this.props而不是this.state中存储状态。由于此组件正在变异items,因此items是状态,应存储在this.state中。 (这是一个good article on props vs. state。)这解决了渲染问题,因为当您更新items时,您将调用setState,这将自动触发重新渲染。

以下是使用状态而不是道具的组件:

var MyList = React.createClass({
    getInitialState: function() {
        return { items: this.props.initialItems };
    },

    toggleHighlight: function() {
        var newItems = this.state.items.map(function (item) {
            item.highlighted = !item.highlighted;
            return item;
        });

        this.setState({ items: newItems });
    },

    render: function() {
        return (
            <div>
                <button onClick={this.toggleHighlight}>Toggle highlight</button>
                { this.state.items.map(function(item) {
                    return <MyComponent key={item.id} text={item.text} 
                             highlighted={item.highlighted}/>;
                }) }
            </div>
        );    
    }
});

React.render( <MyList initialItems={initialItems}/>,
              document.getElementById('container') );

请注意,我将items道具重命名为initialItems,因为它明确表示MyList会改变它。这是recommended by the documentation

您可以在此处查看更新的小提琴:https://jsfiddle.net/kxrf5329/

答案 1 :(得分:6)

您应该通过调用setState()并提供要传播的新道具来触发重新渲染。 如果您确实想强制更新,也可以拨打forceUpdate()

如果查看此page上的示例,您会发现setState是用于更新和触发重新呈现的方法。 documentation也明确表示(ahaha!)。

在你的情况下,我会打电话给forceUpdate

编辑:正如乔丹在评论中所提到的,最好将物品存放为您所在州的一部分。这样您就不必调用forceUpdate,但是您确实会更新组件的状态,因此具有更新值的常规setState会更好。

答案 2 :(得分:4)

我发现使用 key 属性通过 React Hook 重新渲染的不错的解决方案。如果我们更改了子组件或React组件的某些部分的 key 属性,它将完全重新渲染。当您需要重新渲染React Component的某些部分以重新渲染子组件时,它将使用它。这是一个例子。我将重新渲染整个组件。

import React, { useState, useEffect } from "react";
import { PrEditInput } from "./shared";

const BucketInput = ({ bucketPrice = [], handleBucketsUpdate, mood }) => {
  const data = Array.isArray(bucketPrice) ? bucketPrice : [];
  const [state, setState] = useState(Date.now());
  useEffect(() => {
    setState(Date.now());
  }, [mood, bucketPrice]);
  return (
    <span key={state}>
      {data.map((item) => (
        <PrEditInput
          key={item.id}
          label={item?.bucket?.name}
          name={item.bucketId}
          defaultValue={item.price}
          onChange={handleBucketsUpdate}
          mood={mood}
        />
      ))}
    </span>
  );
};

export default BucketInput;

答案 3 :(得分:1)

啊!重新渲染孩子的一个简单方法是每次需要重新渲染时都更新唯一的键属性。

<ChildComponent key={this.state.updatedKey}/>

答案 4 :(得分:0)

您可以在子组件上设置数字键,并在执行操作后触发键更改。例如

state = {
        childKey: 7,
};



<ChildComponent key={this.state.childKey}/>


actionToTriggerReload = () => {
const newKey = this.state.childKey * 89; // this will make sure the key are never the same
this.setState({childKey: newKey})
   }

这肯定会重新渲染ChildComponent