React中如何在Props变化时无需useEffect实现条件数据获取?
不用useEffect也能实现props变化时触发数据获取
当然可以不用useEffect,给你几种实用的实现方式:
1. 子组件内用useRef跟踪props变化,直接触发请求
在组件渲染时,通过useRef记录上一次的props值,对比当前props,不一样就调用useFetch返回的回调。这种方式完全绕开useEffect:
import { useRef } from 'react'; import { useFetch } from './your-useFetch-path'; const DetailModal = ({ selectedRowId }) => { const { data, error, loading, fetchData } = useFetch(); // 记录上一次选中的ID const prevSelectedId = useRef(null); // 每次渲染时检查ID是否变化 if (selectedRowId && selectedRowId !== prevSelectedId.current) { fetchData(`/api/your-endpoint/${selectedRowId}`); prevSelectedId.current = selectedRowId; } return ( <Modal visible={!!selectedRowId}> {loading && <div>加载中...</div>} {error && <div>请求出错:{error}</div>} {data && <div>{JSON.stringify(data)}</div>} </Modal> ); };
注意:这种逻辑是在渲染阶段执行的,要确保fetchData不会触发组件无限重渲染(比如不要在fetchData里直接修改会导致组件重新渲染的状态,除非你的useFetch已经处理好了状态更新的逻辑)。
2. 改造自定义useFetch,让它自动监听依赖变化
把依赖监听的逻辑封装到useFetch内部,子组件只需要传递依赖数组,不用自己写useEffect:
改造后的useFetch Hook:
import { useState, useEffect, useCallback, useRef } from 'react'; export const useFetch = (url, dependencies = []) => { const [data, setData] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const prevUrlRef = useRef(null); const fetchData = useCallback(async () => { if (!url) return; // 避免重复请求相同URL if (prevUrlRef.current === url) return; prevUrlRef.current = url; setLoading(true); try { const res = await fetch(url); const result = await res.json(); setData(result); setError(null); } catch (err) { setError(err.message); setData(null); } finally { setLoading(false); } }, [url]); // Hook内部用useEffect监听依赖,子组件无需关心 useEffect(() => { fetchData(); }, dependencies); return { data, error, loading, fetchData }; };
子组件使用:
const DetailModal = ({ selectedRowId }) => { // 根据选中ID生成请求URL,把selectedRowId作为依赖传递给useFetch const requestUrl = selectedRowId ? `/api/your-endpoint/${selectedRowId}` : null; const { data, error, loading } = useFetch(requestUrl, [selectedRowId]); return ( <Modal visible={!!selectedRowId}> {loading && <div>加载中...</div>} {error && <div>请求出错:{error}</div>} {data && <div>{JSON.stringify(data)}</div>} </Modal> ); };
这种方式对调用方更友好,把副作用逻辑封装在了Hook里,子组件代码更简洁。
3. 把数据获取逻辑移到父组件
父组件选中行时直接发起请求,拿到数据后再传递给Modal子组件,子组件只负责展示:
父组件示例:
import { useState } from 'react'; import { useFetch } from './your-useFetch-path'; const ParentTable = () => { const [selectedRow, setSelectedRow] = useState(null); const [detailData, setDetailData] = useState(null); const { loading, error, fetchData } = useFetch(); const handleRowSelect = async (row) => { setSelectedRow(row); // 选中行后立即发起请求 const result = await fetchData(`/api/your-endpoint/${row.id}`); setDetailData(result); }; return ( <> <Table onRowClick={handleRowSelect} /> <Modal visible={!!selectedRow} data={detailData} loading={loading} error={error} /> </> ); };
这种方式子组件完全不需要处理数据请求,只负责接收props渲染,更符合关注点分离的原则。
内容的提问来源于stack exchange,提问作者iFURY
相关产品推荐
相关产品推荐

