我正在尝试实现一个钩子(useFetch(route, dependencies=[])
),该钩子将用于处理fetch
数据并返回标量值loading
,该值用于确定用户是否当前正在获取新数据。
这在初始呈现中按预期起作用(因为loading
的默认状态为true)。
此问题在以后的每个渲染中都会发生。由于loading
状态当前设置为false
(在初始渲染之后),因此loading
状态将在额外的渲染周期内保持为false,然后再更新为true。 useEffect()
。
如何防止额外的loading=false
渲染周期,所以我在其中使用此useFetch()
的组件会立即意识到当前正在提取数据,并且可以显示'...loading'
文本在render()
中(无需渲染两次即可达到这一点)。
useFetch
function useFetch(route, successHandler, dependencies = []) {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch(route,
{
method: 'POST',
body: JSON.stringify({}),
headers: {"Content-Type": "application/json"}
})
.then(res => res.json())
.then(
() => {
// Set state data from component here
successHandler();
},
() => {/*...*/})
.finally(() => {
setLoading(false);
});
}, dependencies);
return loading;
}
组件
function Component(){
const [toggle, setToggle] = useState(false);
const [options, setOptions] = useState({});
const loading = useFetch('endpoint',
() => setOptions({foo: 'bar'}),
[toggle]);
return <div>
<button onClick={()=>{setToggle(!toggle)}}>Trigger useFetch()</button>
{loading ? '...loading': options.foo}
</div>;
}
任何帮助或设计建议将不胜感激
答案 0 :(得分:2)
您的代码有两个错误:
const loading = useFetch('endpoint',
() => setOptions({foo: 'bar'}),
[toggle]);
useEffect
中使用的变量,在您的情况下可以是[route]
[toggle]
作为依赖项参数将发送[false]
或[true]
,具体取决于您的状态变量。它将不受您创建的钩子的useEffect的控制。 查看此示例,它可以帮助您更好地理解:
答案 1 :(得分:1)
通过此操作,您将更少触发一个渲染,因为切换状态触发了加载状态的状态渲染。除此之外,当状态改变时,它自然会对投降的东西做出反应。希望这会有所帮助。
您也可以将这种效果放在useFetch中。喜欢:
function useFetch(route, successHandler) {
const [loading, setLoading] = useState(false)
const fetchData = useCallback(() => {
function fetchData () {
setLoading(true)
fetch(...)
.then(successHandler)
.finally(() => {
setLoading(false)
})
}
}, [route])
// include route if you want to update the effects on route change too
useEffect(fetchData, [route])
return [fetchData, loading]
}