【问题标题】:React hooks: get current value from child component with no constant rerenderReact hooks:从子组件中获取当前值,无需重新渲染
【发布时间】:2021-03-31 01:35:40
【问题描述】:

页面上有计数器。为了避免每秒重新渲染整个Parent 组件,计数器被放置在一个单独的Child 组件中。

有时需要从计数器Child 获取当前时间(在本例中通过单击按钮)。

我通过传递空对象作为依赖项找到了执行useEffect 的解决方案。 即使它有效,我也不觉得这个解决方案是正确的。 您对如何改进此代码有什么建议吗?

父组件:

const Parent = () => {
  const [getChildValue, setGetChildValue] = useState(0);
  const [triggerChild, setTriggerChild] = useState(0); // set just to force triggering in Child

  const fooJustToTriggerChildAction = () => {
    setTriggerChild({}); // set new empty object to force useEffect in child
  };

  const handleValueFromChild = (timeFromChild) => {
    console.log('Current time from child:', timeFromChild);
  };
  
  return (
    <>
      <Child 
        handleValueFromChild={handleValueFromChild}
        triggerChild={triggerChild}
      /> 
      <Button onPress={fooJustToTriggerChildAction} >
        Click to take time
      </Button>
    </>
  );
};

子组件

const Child = ({
    triggerChild,
    handleValueFromChild,
  }) => {

  const [totalTime, setTotalTime] = useState(0);
  const totalTimeRef = useRef(totalTime); // useRef to handle totalTime inside useEffect

  const counter = () => {
    totalTimeRef.current = totalTimeRef.current + 1;
    setTotalTime(totalTimeRef.current);
    
    setTimeout(counter, 1000);
  };

  useEffect(() => {
    counter();
  }, []); // Run time counter at first render

  useEffect(() => {
    const valueForParent = totalTimeRef.current;
    handleValueFromChild(valueForParent); // use Parent's function to pass new time
  }, [triggerChild]); // Force triggering with empty object

  return (
    <>
      <div>Total time: {totalTime}</div>
    </>
  );
};

【问题讨论】:

  • 您是否总是通过单击按钮来获取当前时间?从子组件中抽出时间的标准是什么?
  • @Konstantin:点击按钮会花费时间,但也会考虑其他功能。喜欢const fooWithOtherRequirements = () =&gt; { /*some code*/ fooJustToTriggerChildAction() }

标签: javascript reactjs react-native react-hooks use-effect


【解决方案1】:

鉴于您的一系列要求,我会做类似的事情,尽管有一点小改动。

我不会传递一个空对象(这显然有效,如 {} !== {}),而是将一个布尔标志传递给我的孩子,请求传回当前的计时器值。一旦传递了值,我就会将标志重置为 false,传递值并等待父级的下一个请求。

父组件:

const Parent = () => {
  const [timerNeeded, setTimerNeeded] = useState(false);

  const fooJustToTriggerChildAction = () => {
    setTimerNeeded(true);
  };

  const handleValueFromChild = (timeFromChild) => {
    console.log('Current time from child:', timeFromChild);
    setTimerNeeded(false);
  };
  
  return (
    <>
      <Child 
        handleValueFromChild={handleValueFromChild}
        timerNeeded={timerNeeded}
      /> 
      <Button onPress={fooJustToTriggerChildAction} >
        Click to take time
      </Button>
    </>
  );
};

子组件

const Child = ({
    timerNeeded,
    handleValueFromChild,
  }) => {

  const [totalTime, setTotalTime] = useState(0);
  const totalTimeRef = useRef(totalTime); // useRef to handle totalTime inside useEffect

  const counter = () => {
    totalTimeRef.current = totalTimeRef.current + 1;
    setTotalTime(totalTimeRef.current);
    
    setTimeout(counter, 1000);
  };

  useEffect(() => {
    counter();
  }, []); // Run time counter at first render

  useEffect(() => {
    if (timerNeeded) {
      handleValueFromChild(totalTimeRef.current);
    }
}, [timerNeeded]);

  return (
    <>
      <div>Total time: {totalTime}</div>
    </>
  );
};

【讨论】:

  • 看起来更好,但是有两个重新渲染而不是一个。谢谢你的想法
猜你喜欢
  • 2020-07-07
  • 2020-02-05
  • 1970-01-01
  • 1970-01-01
  • 2020-06-26
  • 2018-10-07
  • 2020-05-01
  • 1970-01-01
  • 2022-11-21
相关资源
最近更新 更多