useEffect
useEffect
useEffect(() => {
async function fetchData() {
// You can await here
const response = await MyAPI.getData(someId);
// ...
}
fetchData();
}, [someId]); // Or [] if effect doesn't need props or state
- 如果依赖数组为空数组,那么回调函数会在第一次渲染结束后(componentDidMount)执行,返回的函数会在组件卸载时(componentWillUnmount)执行。
- 如果不传依赖数组,那么回调函数会在每一次渲染结束后(
componentDidMount 和componentDidUpdate )执行。 - 如果依赖数组不为空数组,那么回调函数会在依赖值每次更新渲染结束后(componentDidUpdate)执行,这个依赖值一般是
state 或者props 。
受控组件的状态变化
在编写
const defaultProps = {
formData: {},
};
export function VCForm({ formData = defaultProps.formData }) {
// ...
const [innerFormData, setInnerFormData] = React.useState(formData);
// ...
// 当外部 Props 状态变化后,更新数据
React.useEffect(() => {
if (formData) {
setInnerFormData(formData);
}
}, [formData]);
// ...
return (
<Form
value={innerFormDaat}
onChange={(newData) => {
setInnerFormData(newData);
}}
/>
);
}
这里需要注意的是,如果我们直接将默认值写在参数列表里,即 formData = {}
;在外部参数未传入
useLayoutEffect
useEffect 不会block 浏览器渲染,而useLayoutEffect 会。useEffect 会在浏览器渲染结束后执行,useLayoutEffect 则是在DOM 更新完成后,浏览器绘制之前执行。
const moveTo = (dom, delay, options) => {
dom.style.transform = `translate(${options.x}px)`;
dom.style.transition = `left ${delay}ms`;
};
const Animate = () => {
const ref = useRef();
useEffect(() => {
moveTo(ref.current, 500, { x: 600 });
}, []);
return <div ref={ref}>方块</div>;
};
在
useInterval
function Counter() {
const [count, setCount] = useState(0);
useInterval(() => {
setCount(count + 1);
}, 1000);
return <h1>{count}</h1>;
}
import { useEffect, useRef } from "react";
/* istanbul ignore next */
/** keep typescript happy */
const noop = () => {};
export function useInterval(
callback: () => void,
delay: number | null | false,
immediate?: boolean
) {
// Remember the latest callback:
//
// Without this, if you change the callback, when setInterval ticks again, it
// will still call your old callback.
//
// If you add `callback` to useEffect's deps, it will work fine but the
// interval will be reset.
const savedCallback = useRef(noop);
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
});
// Execute callback if immediate is set.
useEffect(() => {
if (!immediate) return;
if (delay === null || delay === false) return;
savedCallback.current();
}, [immediate]);
// Set up the interval.
useEffect(() => {
if (delay === null || delay === false) return undefined;
const tick = () => savedCallback.current();
const id = setInterval(tick, delay);
return () => clearInterval(id);
}, [delay]);
}