如何在 React 渲染之前触发 useEffect?
How to trigger useEffects before render in React?
我有一个从父组件传递到子组件的道具,它根据用户的输入而改变。
我想在呈现子组件之前当 prop 发生变化时触发子组件中的数据获取。我该怎么做?
我尝试使用 useEffects(()=>{},[props.a, props.b])
以下列方式进行尝试,但这总是在渲染之后调用。请帮忙!
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>
);
}
在控制台中我得到的是:
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
如果您知道我如何使代码更高效,那也会有很大的帮助!
这是代码的 codesandbox link:https://codesandbox.io/s/determined-northcutt-6z9f8?file=/src/App.js:0-1466
useEffect 总是在组件的渲染阶段之后调用。这是为了避免在渲染提交阶段发生任何 side-effects(因为它会导致组件变得高度不一致并不断尝试渲染自身)。
- 您的 ParentComponent 由 Input、Input 和 ChildComponent 组成。
- 当您在文本框中键入内容时,
ParentComponent: inputs
状态会被修改。
- 此状态更改导致 ChildComponent 变为 re-render,因此 renderPartOfComponent 被调用(因为 isLoading 在之前的渲染中保持为 false)。
- 在 re-render 之后,将调用 useEffect(Parent 的状态传播到 Child)。
- 由于
isLoading
状态是根据效果修改的,因此会发生另一次渲染。
我通过在 ChildComponent 中创建和维护状态找到了解决方案
所以,进程的顺序是这样的:
道具修改 -> 渲染发生 -> useEffect 块被执行。
我通过简单地在 childComponent 中实例化一个状态并确保 props 状态与渲染前子组件中的状态相同,找到了解决方法,否则它只会显示加载...这非常有效。
您可以使用以下功能:
// utils.js
const useBeforeRender = (callback, deps) => {
const [isRun, setIsRun] = useState(false);
if (!isRun) {
callback();
setIsRun(true);
}
useEffect(() => () => setIsRun(false), deps);
};
// yourComponent.js
useBeforeRender(() => someFunc(), []);
我有一个从父组件传递到子组件的道具,它根据用户的输入而改变。
我想在呈现子组件之前当 prop 发生变化时触发子组件中的数据获取。我该怎么做?
我尝试使用 useEffects(()=>{},[props.a, props.b])
以下列方式进行尝试,但这总是在渲染之后调用。请帮忙!
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>
);
}
在控制台中我得到的是:
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
如果您知道我如何使代码更高效,那也会有很大的帮助!
这是代码的 codesandbox link:https://codesandbox.io/s/determined-northcutt-6z9f8?file=/src/App.js:0-1466
useEffect 总是在组件的渲染阶段之后调用。这是为了避免在渲染提交阶段发生任何 side-effects(因为它会导致组件变得高度不一致并不断尝试渲染自身)。
- 您的 ParentComponent 由 Input、Input 和 ChildComponent 组成。
- 当您在文本框中键入内容时,
ParentComponent: inputs
状态会被修改。 - 此状态更改导致 ChildComponent 变为 re-render,因此 renderPartOfComponent 被调用(因为 isLoading 在之前的渲染中保持为 false)。
- 在 re-render 之后,将调用 useEffect(Parent 的状态传播到 Child)。
- 由于
isLoading
状态是根据效果修改的,因此会发生另一次渲染。
我通过在 ChildComponent 中创建和维护状态找到了解决方案
所以,进程的顺序是这样的: 道具修改 -> 渲染发生 -> useEffect 块被执行。
我通过简单地在 childComponent 中实例化一个状态并确保 props 状态与渲染前子组件中的状态相同,找到了解决方法,否则它只会显示加载...这非常有效。
您可以使用以下功能:
// utils.js
const useBeforeRender = (callback, deps) => {
const [isRun, setIsRun] = useState(false);
if (!isRun) {
callback();
setIsRun(true);
}
useEffect(() => () => setIsRun(false), deps);
};
// yourComponent.js
useBeforeRender(() => someFunc(), []);