【问题标题】:What causes this component to detect changes in its props?是什么导致该组件检测到其 props 的变化?
【发布时间】:2020-02-24 13:46:20
【问题描述】:

在以下最小示例中,父组件具有data 属性并将data.value 传递给子组件。我很难理解更新策略到底发生了什么:

const MY_DATAVALUE = {
  a: 1,
  b: 2
};

const DATA = {
  value: MY_DATAVALUE
};

function Child(props) {
  useEffect(() => {
    console.log("child props changed");
  }, [props]);

  return <h1>Child</h1>;
}

export default function App() {
  const [data, setData] = useState(DATA);

  useEffect(() => {
    console.log("data changed");
  }, [data]);

  useEffect(() => {
    console.log("data.value changed");
  }, [data.value]);

  function handleButtonClick() {
    const newData = {
      value: MY_DATAVALUE
    };
    setData(newData);
  }

  return (
    <>
      <button onClick={handleButtonClick}>Button</button>
      <Child value={data.value} />
    </>
  );
}

(见Codesandbox) 现在,当单击按钮时,我认为会发生以下情况:

  • App 的handleButtonClick() 被执行,data-state 现在指向一个新对象。因此应用的第一个useEffect(检查data)触发。

  • 但是data.value 仍然包含相同的引用(对MY_DATAVALUE),因此App 的第二个useEffect(检查data.value)不会触发。

但是:孩子的useEffect(检查props)触发器。这是为什么?根据家长的说法,data.value 没有改变(否则第二个useEffect 会触发)。

你能解释一下,为什么 Childs useEffect 触发器`?我怎样才能知道道具是否“真的”改变了?我是否必须单独检查所有道具键? 谢谢!

【问题讨论】:

  • 我认为这是因为App 组件的状态作为道具传递给Child 并且App 组件随着状态更新重新渲染,因此孩子们是由于 React 没有对对象内容进行“深度”比较,因此也重新渲染。我认为您需要使用useReducer 进行深度状态对象比较。
  • useMemouseCallback 检查道具的差异。任何更改都会触发使用效果,尽管它是相同的数据

标签: javascript reactjs react-hooks use-effect


【解决方案1】:

useEffect 如果我们提供的内容不同,则依赖项将触发更改。如果我们使用不同的值传递相同的引用或传递不同的引用,就会发生这种情况。

const newData = {
  value: MY_DATAVALUE
};

setData(newData);

data 现在指的是不同的对象,而value 键指的是与之前的值相同的值。

这意味着,这个钩子会触发:

useEffect(() => {
  console.log("data changed");
}, [data]);

虽然这不会触发:

useEffect(() => {
  console.log("data.value changed");
}, [data.value]);

到目前为止,这就是您在这两点中所解释的内容。

对于孩子,props 对象是每次渲染的新引用。

因此,这个钩子总是会触发:

useEffect(() => {
  console.log("child props changed");
}, [props]);

虽然这个钩子不会触发:

const MY_DATAVALUE = {
  a: 1,
  b: 2
};

// In Parent...

<Child value={MY_DATAVALUE} />

// In Child...

useEffect(() => {
  console.log("child value changed");
}, [props.value]);

【讨论】:

  • 感谢您的清晰解释。尤其是“props 对象是每次渲染的新引用”的声明。让我明白了!一件小事:“如果我们用不同的值传递相同的引用”意味着我们用不同的primitive 值传递相同的引用,对吧?
  • @Raphael,不客气!是的,这就是我的意思,对于对象来说,谈论引用和值会让人感到困惑。 {} === {} 将返回 false,而 const a = {} a === a 将返回 true;在primitives 的情况下,正如你所说,123 === 123 将返回 true。
猜你喜欢
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 2015-07-22
  • 1970-01-01
  • 2012-11-07
  • 2017-06-26
  • 2021-04-07
  • 2014-11-09
相关资源
最近更新 更多