如何使用React钩子处理/链接依赖于另一个的同步副作用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用React钩子处理/链接依赖于另一个的同步副作用相关的知识,希望对你有一定的参考价值。
我正在尝试将我的应用程序从redux重写为新的上下文+钩子,但不幸的是,我很难找到一个很好的方法来处理一系列同步副作用,这些副作用取决于之前的响应。
在我目前的redux应用程序中,我大量使用同步/链式操作和API请求,我通常通过redux-saga或thunk来处理。因此,当返回第一个API请求的响应时,该数据将用于下一个API请求等。
我已经制作了一个自定义钩子“useFetch”(在这个例子中它没有做太多,因为它是一个简化版本,我也不得不做一个小调整,以便在codeandbox上工作 - 请参阅下面的代码)。问题在于,由于“钩子规则”,我不能在useEffect钩子中使用自定义钩子。那么如果你有自己的钩子来获取数据,如何等待第一个请求在做下一个请求之前的响应?即使我最终放弃了useFetch抽象并创建了一个vanilla fetch请求,如何避免结束许多useEffects钩子的臃肿混乱?这可以做得更优雅一点,还是上下文+钩子仍然为时过早与redux saga / thunk竞争处理副作用?
下面的示例代码非常简单。应该尝试模拟的是:
- 查询人api端点以获取此人
- 一旦我们有人响应,查询作业端点(使用真实世界场景中的人员ID)
- 一旦我们有了人和工作,根据人员和工作终端的响应,查询同事端点,找到特定工作的同事。
这是代码。添加了useFetch挂钩的延迟来模拟现实世界中的延迟:
import React, { useEffect, useState } from "react";
import { render } from "react-dom";
import "./styles.css";
const useFetch = (url, delay = 0) => {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
// const result = await fetch(url, {
// method: "GET",
// headers: { "Content-Type": "application/json" }
// });
//const response = await result.json();
const response = await import(url);
setTimeout(function() {
setData(response);
}, delay);
};
fetchData();
}, [url]);
return data;
};
function App() {
const [person, setPerson] = useState();
const [job, setJob] = useState();
const [collegues, setCollegues] = useState();
// first we fetch the person /api/person based on the jwt most likely
const personData = useFetch("./person.json", 5000);
// now that we have the person data, we use the id to query for the
// persons job /api/person/1/jobs
const jobData = useFetch("./job.json", 3000);
// now we can query for a persons collegues at job x /api/person/1/job/1/collegues
const colleguesData = useFetch("./collegues.json", 1000);
console.log(personData);
console.log(jobData);
console.log(colleguesData);
// useEffect(() => {
// setPerson(useFetch("./person.json", 5000));
// }, []);
// useEffect(() => {
// setJob(useFetch("./job.json", 3000));
// }, [person]);
// useEffect(() => {
// setCollegues(useFetch("./collegues.json",1000));
// }, [job]);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);
运行示例:https://codesandbox.io/s/2v44lron3n?fontsize=14(您可能需要进行更改 - 空格或删除分号 - 以使其工作)
希望这样的东西(或更好的解决方案)是可能的,否则我将无法从令人敬畏的redux-saga / thunk迁移到context + hooks。
钩子不会取代你处理异步动作的方式,它们只是你曾经做过的一些事情的抽象,比如调用componentDidMount
,或者处理state
等。
在您给出的示例中,您不需要自定义挂钩:
function App() {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
const job = await import("./job.json");
const collegues = await import("./collegues.json");
const person = await import("./person.json");
setData({
job,
collegues,
person
})
};
fetchData()
}, []);
return <div className="App">{JSON.stringify(data)}</div>;
}
话虽这么说,也许如果你提供一个你想要重构的实际redux-saga或thunk代码的例子,我们可以看看实现它的步骤是什么。
编辑:
话虽如此,如果你还想做这样的事情,你可以看看这个:
https://github.com/dai-shi/react-hooks-async
import React from 'react';
import { useFetch } from 'react-hooks-async/dist/use-async-task-fetch';
const UserInfo = ({ id }) => {
const url = `https://reqres.in/api/users/${id}?delay=1`;
const { pending, error, result, abort } = useFetch(url);
if (pending) return <div>Loading...<button onClick={abort}>Abort</button></div>;
if (error) return <div>Error:{error.name}{' '}{error.message}</div>;
if (!result) return <div>No result</div>;
return <div>First Name:{result.data.first_name}</div>;
};
const App = () => (
<div>
<UserInfo id={'1'} />
<UserInfo id={'2'} />
</div>
);
这是现实生活中的常见情况,您希望等待第一次提取完成,然后执行下一次提取。
请查看新的代码框:https://codesandbox.io/s/p92ylrymkj
你在获取请求时使用了生成器。以正确的顺序检索数据。单击“获取数据”按钮后,转到控制台并查看。
希望这是你正在寻找的。
我相信你会遇到这个问题,因为fetch钩子的实现很差,这个例子对我们来说太基本了解。如果您在同一个组件中使用工作,同事和人员,您应该明确说明。如果是这样,将它们分开就更明智了。
话虽如此,让我举一个我自己的fetch钩子的例子:
const { loading, error, value } = useResource<Person>(getPerson, personId)
我有这样一个钩子,它有自己的加载,错误,值等状态。 它需要两个参数: - 获取方法 - 获取方法参数
拥有这样的结构,您可以将资源链接在一起。 useResource实现只是创建一个状态并在useEffect中,检查属性是否更改等。如果更改,则调用fetch方法。
以上是关于如何使用React钩子处理/链接依赖于另一个的同步副作用的主要内容,如果未能解决你的问题,请参考以下文章
给定两个 Linux 静态库,如何判断一个是不是依赖于另一个?
如何在 useEffect 中使用 setTimeout 重置 React 钩子状态