等待来自未知 children 组件编号的值,然后生效
Waiting for values from unknown children component number before effet
假设有一个 parent 分量:
function Parent({ children }) {
useEffet(() => {
// Do something when all children
// have returned their values via props (or context)
})
return <div>{ children }</div>
}
如何才能运行只在所有children都做了某事之后才生效?我不知道 children 的确切数量,它可能会有所不同:
// In this example there are 4 children
function App() {
return (
<Parent>
<Children />
<Children />
<Children />
<div>
<Children />
</div>
</Parent>
);
}
实际问题是所有 children 都可以准备查询(假设是 ElasticSearch 查询),而 parent 负责实际执行整个查询。
当所有 children 完成后,您可以引入一个 finish
状态 "doing something".
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
并向 children 组件添加 "updating finish state" 功能。
好吧,我们可以将 Children 执行的操作包装到 Promise 中:
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
传递给children并在那里使用它(在Children内):
const queryArrived = useQueryArrived();
// somewhen:
queryArrived({ some: "props" });
现在逻辑如下:
Parent 第一次渲染时,会创建 promises
数组。 childrens 将被初始化,并且它们中的每一个都创建一个附加到 promises
的 Promise,Promise 的解析器被记忆化,以便在每次 child 重新渲染时返回相同的解析器。当所有 children 都初始化后,React 渲染并触发效果,这将接受所有承诺并对其调用 Promise.all
。
现在,当 queryArrived
在 children 中被调用时,promises 解决,当最后一个 promise 解决时,然后调用 setResult
所有的 promises 结果将导致在 Parent 上重新渲染,现在可以使用查询。
假设有一个 parent 分量:
function Parent({ children }) {
useEffet(() => {
// Do something when all children
// have returned their values via props (or context)
})
return <div>{ children }</div>
}
如何才能运行只在所有children都做了某事之后才生效?我不知道 children 的确切数量,它可能会有所不同:
// In this example there are 4 children
function App() {
return (
<Parent>
<Children />
<Children />
<Children />
<div>
<Children />
</div>
</Parent>
);
}
实际问题是所有 children 都可以准备查询(假设是 ElasticSearch 查询),而 parent 负责实际执行整个查询。
当所有 children 完成后,您可以引入一个 finish
状态 "doing something".
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
并向 children 组件添加 "updating finish state" 功能。
好吧,我们可以将 Children 执行的操作包装到 Promise 中:
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
传递给children并在那里使用它(在Children内):
const queryArrived = useQueryArrived();
// somewhen:
queryArrived({ some: "props" });
现在逻辑如下:
Parent 第一次渲染时,会创建 promises
数组。 childrens 将被初始化,并且它们中的每一个都创建一个附加到 promises
的 Promise,Promise 的解析器被记忆化,以便在每次 child 重新渲染时返回相同的解析器。当所有 children 都初始化后,React 渲染并触发效果,这将接受所有承诺并对其调用 Promise.all
。
现在,当 queryArrived
在 children 中被调用时,promises 解决,当最后一个 promise 解决时,然后调用 setResult
所有的 promises 结果将导致在 Parent 上重新渲染,现在可以使用查询。