功能子组件不会在道具变更时重新显示

时间:2020-03-15 23:26:03

标签: javascript reactjs react-hooks

我有一个非常繁重的(从计算上来说)功能组件(Parent),它没有状态,并且具有局部状态的Child子组件很少。孩子仅依赖于父母发送的道具。

我将一个函数传递给子项之一(ChildA),以更改父项上变量的值。

此变量是不同子组件(ChildB)的道具之一,该子组件具有基于该道具的状态并在useEffect挂钩中对其进行更新。

当作为prop传递的值在Parent组件上更改时,ChildB组件不会重新呈现。

当然,在Parent上引入状态(useState钩子)可以解决此问题,但是一遍又一遍地重新渲染父级,并会降低性能,因为Parent具有500多个嵌套组件,所有组件都会重新渲染。

引入某种类型的商店(Redux,MobX)可能会解决此问题,但是这可能是一个过大的杀伤力。

一个简化的示例:

import React, { useEffect, useState } from "react";

export default function App() {
  return <Parent />    
}

const ChildA = ({ onAction }) => {
  return <button onClick={onAction}>CLICK</button>;
};

const ChildB = ({ coreValue }) => {
  const [value, setValue] = useState(0);

  useEffect(() => {
    setValue(coreValue);
  }, [coreValue]);

  return <div>My value: {value}</div>;
};

const Parent = () => {
  let calculatedValue = 0;

  const changeValue = () => {
    calculatedValue += Math.random();
  };

  return (
    <div>
      <ChildA onAction={changeValue} />
      <ChildB coreValue={calculatedValue} />
    </div>
  );
};

您可以在此处测试代码:https://codesandbox.io/s/vigilant-wave-r27rg

如何仅在更改道具时重新渲染ChildB?

2 个答案:

答案 0 :(得分:0)

您必须将值存储在父组件状态中,只需将父组件状态值发送到ChildB,就无需维护状态,也不需要使用Effect钩子来捕获更改。在此处查看代码:https://codesandbox.io/s/adoring-chatelet-sjjfs

import React, { useState } from "react";
export default function App() {
  return <Parent />;
}
const ChildA = ({ onAction }) => {
  return <button onClick={onAction}>CLICK</button>;
};
const ChildB = ({ coreValue }) => {
  return <div>My value: {coreValue}</div>;
};
const Parent = () => {
  const [value, setValue] = useState(0);
  const changeValue = () => {
    setValue(value + Math.random());
  };
  return (
    <div>
       <ChildA onAction={changeValue} />
       <ChildB coreValue={value} />
    </div>
  );
};

答案 1 :(得分:0)

反应的useCallbackmemo防止不必要的重新渲染。请注意,无论ParentChildB状态更改的次数如何,ChildA都不会重新渲染。另外,您当前的示例不需要useState

中的useEffect / ChildB

https://codesandbox.io/s/usecallback-and-memo-ptkuj

import React, { useEffect, useState, memo, useCallback } from "react";

export default function App() {
  return <Parent />;
}

const ChildA = memo(({ onAction }) => {
  console.log("ChildA rendering");
  return <button onClick={onAction}>CLICK</button>;
});

const ChildB = memo(({ coreValue }) => {
  const [value, setValue] = useState(0);

  useEffect(() => {
    setValue(coreValue);
  }, [coreValue]);

  return <div>My value: {value}</div>;
});

const Parent = () => {
  const [calculatedValue, setCalculatedValue] = useState(0);

  const changeValue = useCallback(() => {
    setCalculatedValue(c => (c += Math.random()));
  }, []);

  return (
    <div>
      <ChildA onAction={changeValue} />
      <ChildB coreValue={calculatedValue} />
    </div>
  );
};