为什么在下面的伪代码示例中,当容器更改foo.bar时,子不重新呈现?

Container {
  handleEvent() {
    this.props.foo.bar = 123
  },

  render() {
    return <Child bar={this.props.foo.bar} />
}

Child {
  render() {
    return <div>{this.props.bar}</div>
  }
}

即使我在修改Container中的值后调用forceUpdate(), Child仍然显示旧值。


当前回答

因为如果父对象的道具改变了,子对象不会重新渲染,但是如果它的STATE改变了:)

你所展示的是: https://facebook.github.io/react/tips/communicate-between-components.html

它将通过道具将数据从父对象传递到子对象,但没有渲染逻辑。

你需要为父节点设置一些状态,然后在父节点更改状态上重新渲染子节点。 这可能会有所帮助。 https://facebook.github.io/react/tips/expose-component-functions.html

其他回答

我也遇到了同样的问题。 我有一个Tooltip组件,它正在接收showTooltip道具,我正在基于if条件在父组件上更新,它正在父组件中更新,但Tooltip组件没有呈现。

const Parent = () => {
   let showTooltip = false;
   if(....){ showTooltip = true; }
   return(
      <Tooltip showTooltip={showTooltip}></Tooltip>
   )
}

我犯的错误是将showTooltip声明为let。

我意识到我做错了什么,我违反了渲染工作的原则,用钩子代替它。

const [showTooltip, setShowTooltip] =  React.useState<boolean>(false);

我也有同样的问题。 这是我的解决方案,我不确定这是一个好的实践,如果不是告诉我:

state = {
  value: this.props.value
};

componentDidUpdate(prevProps) {
  if(prevProps.value !== this.props.value) {
    this.setState({value: this.props.value});
  }
}

UPD:现在你可以用React Hooks做同样的事情: (仅当component是函数时)

const [value, setValue] = useState(propName);
// This will launch only if propName value has chaged.
useEffect(() => { setValue(propName) }, [propName]);

遵守不变性

这是一个很老的问题,但它是一个常青的问题,如果只有错误的答案和变通方法,它不会变得更好。 子对象不更新的原因不是缺少键或缺少状态,而是你没有遵守不变性原则。

It is the aim of react to make apps faster and more responsive and easier to maintain and so on but you have to follow some principles. React nodes are only rerendered if it is necessary, i.e. if they have updated. How does react know if a component has updated? Because it state has changed. Now don't mix this up with the setState hook. State is a concept and every component has its state. State is the look or behaviour of the component at a given point in time. If you have a static component you only have one state all the time and don't have to take care of it. If the component has to change somehow its state is changing.

Now react is very descriptive. The state of a component can be derived from some changing information and this information can be stored outside of the component or inside. If the information is stored inside than this is some information the component has to keep track itself and we normally use the hooks like setState to manage this information. If this information is stored outside of our component then it is stored inside of a different component and that one has to keep track of it, its theirs state. Now the other component can pass us their state thru the props.

That means react rerenders if our own managed state changes or if the information coming in via props changes. That is the natural behaviour and you don't have to transfer props data into your own state. Now comes the very important point: how does react know when information has changed? Easy: is makes an comparison! Whenever you set some state or give react some information it has to consider, it compares the newly given information with the actually stored information and if they are not the same, react will rerender all dependencies of that information. Not the same in that aspect means a javascript === operator. Maybe you got the point already. Let's look at this:

设a = 42; 令b = a; Console.log('是否a与b相同?',a === b);// a和b是一样的,对吗?——>真正 A += 5;//现在让我们改变a Console.log (' a是否仍然与b相同?',a === b);//——> false

我们创建一个值的实例,然后创建另一个实例,将第一个实例的值赋给第二个实例,然后更改第一个实例。 现在让我们看看相同的对象流:

设a = {num: 42}; 令b = a; Console.log('是否a与b相同?',a === b);// a和b是一样的,对吗?——>真正 A.num += 5;//现在让我们改变a Console.log (' a是否仍然与b相同?',a === b);//——> true 这次的不同之处在于,对象实际上是指向内存区域的指针,通过断言b=a,您将b设置为指向完全相同对象的与a相同的指针。 你在a中做的任何事情都可以被a指针或b指针访问。 你的线:

this.props.foo.bar = 123

actually updates a value in the memory where "this" is pointing at. React simply can't recognize such alterations by comparing the object references. You can change the contents of your object a thousand times and the reference will always stay the same and react won't do a rerender of the dependent components. That is why you have to consider all variables in react as immutable. To make a detectable change you need a different reference and you only get that with a new object. So instead of changing your object you have to copy it to a new one and then you can change some values in it before you hand it over to react. Look: let a = {num: 42}; console.log('a looks like', a); let b = {...a}; console.log('b looks like', b); console.log('is a the same as b?', a === b); // --> false The spread operator (the one with the three dots) or the map-function are common ways to copy data to a new object or array.

如果你遵守不可变性,所有的子节点更新新的道具数据。

我的案例涉及在props对象上有多个属性,并且需要在更改其中任何一个时重新渲染Child。 上面提供的解决方案是有效的,但为每个方案添加一个密钥变得乏味和肮脏(想象一下有15个……)如果有人面临这个问题,你可能会发现stringify props对象很有用:

<Child
    key={JSON.stringify(props)}
/>

这样,对props上的每个属性的每次更改都会触发Child组件的重新呈现。

希望这能帮到别人。

在我的例子中,我正在更新传递给组件的加载状态。在按钮内的道具。加载是通过预期的(从假切换为真),但显示旋转器没有更新的三元。

我尝试添加一个键,添加一个状态,更新useEffect()等,但没有其他答案工作。

对我有效的是改变这一点:

setLoading(true);
handleOtherCPUHeavyCode();

:

setLoading(true);
setTimeout(() => { handleOtherCPUHeavyCode() }, 1)

我认为这是因为handleOtherCPUHeavyCode中的进程非常繁重和密集,所以应用程序会冻结一秒钟左右。添加1ms超时允许加载布尔值更新,然后繁重的代码函数可以完成它的工作。