为什么在下面的伪代码示例中,当容器更改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仍然显示旧值。


当前回答

更新子进程以使属性'key'与名称相等。每次键改变时,组件都会重新呈现。

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

其他回答

考虑到道具的渲染限制和状态的增益,如果你使用反应钩子,你可以使用一些技巧。例如,您可以使用useEffect手动将道具转换为状态。这可能不是最好的做法,但在这些情况下是有帮助的。

import { isEqual } from 'lodash';
import { useEffect, useState } from 'react';

export const MyComponent = (props: { users: [] }) => {
  const [usersState, setUsersState] = useState([]);

  useEffect(() => {
    if (!isEqual(props.users, usersState)) {
      setUsersState(props.users);
    }
  }, [props.users]);

  <OtherComponent users={usersState} />;
};

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

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

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

希望这能帮到别人。

更新子进程以使属性'key'与名称相等。每次键改变时,组件都会重新呈现。

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

我有同样的问题的重新渲染对象道具,如果道具是一个对象JSON.stringify(obj),并将其设置为功能组件的关键。为react钩子设置一个id键对我来说并不适用。奇怪的是,要更新组件,你必须在键上包含所有对象属性并将其连接到那里。

function Child(props) {
  const [thing, setThing] = useState(props.something)
  
  return (
   <>
     <div>{thing.a}</div>
     <div>{thing.b}</div>
   </>
  )
}

...

function Caller() {
   const thing = [{a: 1, b: 2}, {a: 3, b: 4}]
   thing.map(t => (
     <Child key={JSON.stringify(t)} something={thing} />
   ))
}

现在,任何时候thing对象在运行时改变了它的值,子组件将正确地重新呈现它。

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

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

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

setLoading(true);
handleOtherCPUHeavyCode();

:

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

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