在effet之前等待来自未知子组件编号的值

问题描述 投票:1回答:2

假设有一个父组件:

function Parent({ children }) {
  useEffet(() => {
    // Do something when all children 
    // have returned their values via props (or context)
  })
  return <div>{ children }</div>
}

只有在所有孩子都做了什么之后我才能运行效果?我不知道孩子的确切人数,可能会有所不同:

// In this example there are 4 children
function App() {
  return (
    <Parent>
      <Children />
      <Children />
      <Children />
      <div>
        <Children />
      </div>
    </Parent>
  );
}

实际问题是所有孩子都可以准备一个查询(假设是一个ElasticSearch查询),父母负责实际执行整个查询。

javascript reactjs react-hooks
2个回答
1
投票

好吧,我们可以将儿童所做的行动包装成一个承诺:

  function usePromises() {
    const promises = useMemo([], []);
    const [result, setResult] = useState(undefined);

    useEffect(() => { // this gets deferred after the initialization of all childrens, therefore all promises were created already
          Promise.all(promises).then(setResult);
     }, []);


    function usePromise() {
      return useMemo(() => {
       let resolve;
       promises.push(new Promise(r => resolve = r));
       return resolve;
      }, []);
    }

   return [result, usePromise];
}

现在创建一个共享管理器(在Parent内部):

  const [queries, useQueryArrived] = usePromises();
  // queries is either undefined or an array of queries, if all queries arrived this component will rerender
  console.log(queries);

然后将useQueryArrived传给孩子并在那里使用(在孩子们内部):

  const queryArrived = useQueryArrived();

  // somewhen:
  queryArrived({ some: "props" });

现在的逻辑如下:

Parent第一次渲染,它将创建promises数组。孩子们将被初始化,他们每个人都会创建一个附加到promises的Promise,Promise的解析器会被记忆,这样每个孩子的重新渲染都会返回相同的解析器。当所有的孩子都被初始化时,React渲染并且效果被触发,这将获得所有的承诺,并在他们身上调用Promise.all

现在,当queryArrived在孩子们中被召唤时,承诺会解决,有些人会在最后一个承诺解决之后,然后将所有承诺结果调用setResult,这将导致对父亲的重新渲染,现在可以使用查询。


1
投票

当所有孩子完成“做某事”时,你可以介绍一个finish状态。

  useEffect(() => {
    const totalChildren = React.Children.count(children);
    if (totalChildren === finish) {
      console.log("All Children Done Something");
      setFinished(0);
    }
  }, [finish]);

对于example

function Children({ num, onClick }) {
  return <button onClick={onClick}>{num}</button>;
}
function Parent({ finish, setFinished, children }) {
  useEffect(() => {
    const totalChildren = React.Children.count(children);
    if (totalChildren === finish) {
      console.log("All Children Done Something");
      setFinished(0);
    }
  }, [finish]);
  return <div>{children}</div>;
}

function App() {
  const [num, setNum] = useState(0);
  const [finish, setFinished] = useState(0);

  const onClick = () => {
    setNum(num + 1);
    setFinished(finish + 1);
  };
  return (
    <Parent finish={finish} setFinished={setFinished}>
      <Children num={num} onClick={onClick} />
      <Children num={num + 1} onClick={onClick} />
      <Children num={num + 2} onClick={onClick} />
      <div>
        <Children num={num + 3} onClick={onClick} />
      </div>
    </Parent>
  );
}

此外,您可以使用React.cloneElement并为子组件添加“更新完成状态”功能。

© www.soinside.com 2019 - 2024. All rights reserved.