[英]How to trigger useEffects before render in React?
I have a prop being passed from a parent component to a child component which changes based on the user's input.我有一个从父组件传递到子组件的道具,该道具会根据用户的输入而变化。
I want to trigger a data fetch in the child component when that prop changes before the child component is rendered.我想在子组件渲染之前该道具发生变化时触发子组件中的数据获取。 How can I do it?
我该怎么做?
I tried in the following manner by using useEffects(()=>{},[props.a, props.b])
but that is always called after the render.我通过使用
useEffects(()=>{},[props.a, props.b])
尝试了以下方式,但这总是在渲染之后调用。 Please help!请帮忙!
import React, { useEffect, useState } from "react";
import "./styles.css";
export default function parentComponent() {
const [inputs, setInputs] = useState({ a: "", b: "" });
return (
<>
<input
value={inputs.a}
onChange={(event) => {
const value = event.target.value;
setInputs((prevState) => {
return { ...prevState, a: value };
});
}}
/>
<input
value={inputs.b}
onChange={(event) => {
const value = event.target.value;
setInputs((prevState) => {
return { ...prevState, b: value };
});
}}
/>
<ChildComponent a={inputs.a} b={inputs.b} />
</>
);
}
function ChildComponent(props) {
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState({});
useEffect(() => {
console.log("updating new data based on props.a: " + props.a);
setData({ name: "john " + props.a });
return () => {};
}, [props.a, props.b]);
useEffect(() => {
console.log("data successfully changed");
console.log(data);
if (Object.keys(data).length !== 0) {
setIsLoading(false);
}
return () => {};
}, [data]);
function renderPartOfComponent() {
console.log("rendering POC with props.a: " + props.a);
return <div>data is: {data.name}</div>;
}
return (
<div className="App">{isLoading ? null : renderPartOfComponent()}</div>
);
}
In the console what I get is:在控制台中,我得到的是:
rendering POC with props.a: fe
rendering POC with props.a: fe
updating new data based on props.a: fe
rendering POC with props.a: fe
rendering POC with props.a: fe
data successfully changed
Object {name: "john fe"}
rendering POC with props.a: fe
rendering POC with props.a: fe
If you know how I can make the code more efficient, that would be a great help as well!如果您知道我如何使代码更高效,那也将是一个很大的帮助!
Here's the codesandbox link for the code: https://codesandbox.io/s/determined-northcutt-6z9f8?file=/src/App.js:0-1466这是代码的代码框链接: https ://codesandbox.io/s/determined-northcutt-6z9f8?file=/src/App.js:0-1466
I found the solution by creating and maintaining state within the ChildComponent我通过在 ChildComponent 中创建和维护状态找到了解决方案
So, the order of processes was this: props modified -> render takes place -> useEffect block is executed.所以,进程的顺序是这样的:修改道具 -> 渲染发生 -> 执行 useEffect 块。
I found the workaround by simply instantiating a state within the childComponent and making sure that the props state is the same as the one in the child component before rendering, else it would just show loading... This works perfectly.我通过简单地在 childComponent 中实例化一个状态并确保 props 状态与渲染之前的子组件中的状态相同来找到解决方法,否则它只会显示加载......这非常有效。
useEffect is always called after the render phase of the component. useEffect总是在组件的渲染阶段之后调用。 This is to avoid any side-effects from happening during the render commit phase (as it'd cause the component to become highly inconsistent and keep trying to render itself).
这是为了避免在渲染提交阶段发生任何副作用(因为它会导致组件变得高度不一致并继续尝试渲染自身)。
ParentComponent: inputs
state is modified.ParentComponent: inputs
状态被修改。isLoading
state is modified from the effects, another rendering happens.isLoading
状态是从效果中修改的,因此会发生另一次渲染。You can use function below:您可以使用以下功能:
// utils.js
const useBeforeRender = (callback, deps) => {
const [isRun, setIsRun] = useState(false);
if (!isRun) {
callback();
setIsRun(true);
}
useEffect(() => () => setIsRun(false), deps);
};
// yourComponent.js
useBeforeRender(() => someFunc(), []);
You can use useMemo
, which doesn't wait for re-render
.您可以使用
useMemo
,它不等待re-render
。 It will execute as long as the dependencies are changed.只要依赖关系发生变化,它就会执行。
useMemo(()=>{
doSomething() //Doesn't want until render is completed
}, [dep1, dep2])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.