避免组件重渲染后重复发起数据请求
解决组件卸载重挂载导致重复API请求的问题
你当前的问题根源在于:Parent组件用{toggle && <Child />}做条件渲染,当toggle从true切到false时,Child会被卸载;再切回true时,Child重新挂载,所以Child里的useEffect(空依赖数组)会再次执行,导致重复触发请求。
下面是几种可行的解决思路:
思路1:把请求逻辑提到父组件
将API请求放在Parent组件中,拿到数据后通过props传递给Child。这样无论Child是否挂载,数据都保存在Parent的状态里,只会发起一次请求。
修改后的代码:
import { useEffect, useState } from 'react'; function Child({ data }) { return <div>{data}</div>; } export default function Parent() { const [toggle, setToggle] = useState(false); const [data, setData] = useState(""); // 在父组件中发起请求,仅执行一次 useEffect(() => { console.log("fetching some data from server"); setData(`this number should not change: ${Math.random().toString()}`); }, []); const onToggle = () => { setToggle(!toggle); }; return ( <> <button onClick={onToggle}>Toggle</button> {toggle && <Child data={data} />} </> ); }
思路2:不让Child被卸载,用CSS控制显示隐藏
不通过条件渲染移除Child组件,而是用CSS的display属性控制显隐,这样Child始终保持挂载状态,useEffect只会执行一次。
修改后的代码:
import { useEffect, useState } from 'react'; function Child() { const [data, setData] = useState(""); useEffect(() => { console.log("fetching some data from server"); setData(`this number should not change: ${Math.random().toString()}`); }, []); return <div>{data}</div>; } export default function Parent() { const [toggle, setToggle] = useState(false); const onToggle = () => { setToggle(!toggle); }; return ( <> <button onClick={onToggle}>Toggle</button> {/* 用CSS控制显隐,Child始终处于挂载状态 */} <Child style={{ display: toggle ? "block" : "none" }} /> </> ); }
思路3:用全局状态存储数据(以Context为例)
如果多个组件需要复用这份数据,或者组件层级较深,可以将数据放到全局状态中,请求一次后全项目复用。这里用React Context做示例:
import { createContext, useContext, useEffect, useState } from 'react'; // 创建数据Context const DataContext = createContext(); // 封装Provider组件统一管理数据 function DataProvider({ children }) { const [data, setData] = useState(""); useEffect(() => { console.log("fetching some data from server"); setData(`this number should not change: ${Math.random().toString()}`); }, []); return ( <DataContext.Provider value={data}> {children} </DataContext.Provider> ); } function Child() { // 从Context中获取数据 const data = useContext(DataContext); return <div>{data}</div>; } export default function Parent() { const [toggle, setToggle] = useState(false); const onToggle = () => { setToggle(!toggle); }; return ( <DataProvider> <button onClick={onToggle}>Toggle</button> {toggle && <Child />} </DataProvider> ); }
内容的提问来源于stack exchange,提问作者Luvias
相关产品推荐
相关产品推荐

