为什么在下面的伪代码示例中,当容器更改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 = {
  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]);

其他回答

如果Child不维护任何状态,而只是呈现道具,然后从父组件调用它,那么您可能应该将它作为功能组件。除此之外,您还可以使用与功能组件(useState)的挂钩,这将导致无状态组件重新呈现。

此外,您不应该更改propas,因为它们是不可变的。维护组件的状态。

Child = ({bar}) => (bar);

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

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

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

setLoading(true);
handleOtherCPUHeavyCode();

:

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

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

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

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

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

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

你应该使用setState函数。如果不是,无论如何使用forceUpdate, state都不会保存您的更改。

Container {
    handleEvent= () => { // use arrow function
        //this.props.foo.bar = 123
        //You should use setState to set value like this:
        this.setState({foo: {bar: 123}});
    };

    render() {
        return <Child bar={this.state.foo.bar} />
    }
    Child {
        render() {
            return <div>{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} />;
};