Javascript 如何使用React钩子处理/链接依赖于另一个钩子的同步副作用
我试图将我的应用程序从redux重写为新的context+钩子,但不幸的是,我很难找到一个好方法来处理一系列同步副作用,这些副作用取决于前一个版本的响应 在我当前的redux应用程序中,我大量使用了同步/链接操作和API请求,我通常通过redux saga或thunks来处理这些请求。因此,当返回第一个API请求的响应时,该数据将用于下一个API请求等 我已经制作了一个定制的钩子“useFetch”(在本例中,它做的不多,因为它是一个简化的版本,我还必须对它进行一些小的调整,以便在codesandbox上工作-请参阅下面的代码)。问题是由于“钩子规则”,我不能在useEffect钩子中使用自定义钩子。那么,如果您有自己的获取数据的钩子,那么如何在执行下一个etc之前等待第一个请求的响应呢?即使我最终放弃了useFetch抽象并创建了一个普通的fetch请求,如何避免最终出现大量useEffects钩子的臃肿混乱呢?这可以做得更优雅一点吗,或者上下文+挂钩在处理副作用方面与redux saga/thunk竞争还为时过早吗 下面的示例代码非常简单。它应该尝试模拟的是:Javascript 如何使用React钩子处理/链接依赖于另一个钩子的同步副作用,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我试图将我的应用程序从redux重写为新的context+钩子,但不幸的是,我很难找到一个好方法来处理一系列同步副作用,这些副作用取决于前一个版本的响应 在我当前的redux应用程序中,我大量使用了同步/链接操作和API请求,我通常通过redux saga或thunks来处理这些请求。因此,当返回第一个API请求的响应时,该数据将用于下一个API请求等 我已经制作了一个定制的钩子“useFetch”(在本例中,它做的不多,因为它是一个简化的版本,我还必须对它进行一些小的调整,以便在codesan
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);
import React,{useffect,useState}来自“React”;
从“react dom”导入{render};
导入“/styles.css”;
const useFetch=(url,延迟=0)=>{
const[data,setData]=useState(null);
useffect(()=>{
const fetchData=async()=>{
//const result=等待获取(url{
//方法:“获取”,
//标题:{“内容类型”:“应用程序/json”}
// });
//const response=wait result.json();
const response=等待导入(url);
setTimeout(函数(){
setData(响应);
},延误);
};
fetchData();
},[url]);
返回数据;
};
函数App(){
const[person,setPerson]=useState();
const[job,setJob]=useState();
const[collegues,setCollegues]=useState();
//首先,我们最有可能基于jwt获取person/api/person
const personData=useFetch(“./person.json”,5000);
//现在我们有了person数据,我们使用id来查询
//人员职务/api/人员/1/职务
const jobData=useFetch(“./job.json”,3000);
//现在我们可以在job x/api/person/1/job/1/collegues处查询人员同事
const colleguesData=useFetch(“./collegues.json”,1000);
console.log(personData);
console.log(jobData);
控制台日志(收集数据);
//useffect(()=>{
//setPerson(useFetch(“./person.json”,5000));
// }, []);
//useffect(()=>{
//setJob(useFetch(“./job.json”,3000));
//},[人];
//useffect(()=>{
//setCollegues(useFetch(“./collegues.json”,1000));
//[工作];
返回(
你好,代码沙盒
开始编辑,看看神奇的发生!
);
}
const rootElement=document.getElementById(“根”);
render((您可能需要更改空格或删除分号以使其工作)
希望这样的事情(或者更好的解决方案)是可能的,否则我将无法从令人敬畏的redux saga/thunks迁移到context+挂钩
最佳答案:钩子不会取代处理异步操作的方式,它们只是对您过去所做的一些事情的抽象,比如调用组件didmount
,或者处理状态
,等等
在您给出的示例中,您实际上不需要自定义挂钩:
函数应用程序(){
const[data,setData]=useState(null);
useffect(()=>{
const fetchData=async()=>{
const job=等待导入(“./job.json”);
const collegues=等待导入(“./collegues.json”);
const person=等待导入(“./person.json”);
设置数据({
工作,
学院,
人
})
};
fetchData()
}, []);
返回{JSON.stringify(data)};
}
也就是说,如果您提供了一个实际的redux saga或thunks代码的示例,您希望重构,我们可以看到实现这一点的步骤
编辑:
也就是说,如果你还想做这样的事情,你可以看看这个:
从“React”导入React;
从'react hooks async/dist/use async task fetch'导入{useFetch};
const UserInfo=({id})=>{
常量url=`https://reqres.in/api/users/${id}?延迟=1`;
const{pending,error,result,abort}=useFetch(url);
如果(待定)返回加载…中止;
if(error)返回错误:{error.name}{'}{error.message};
如果(!result)不返回结果;
返回名字:{result.data.First_Name};
};
常量应用=()=>(
);
编辑
这是一种有趣的方法这是现实生活中常见的场景,您希望等待第一次提取完成,然后执行下一次提取
请查看新的代码沙盒:
当您执行提取请求时,我使用了generator。按照正确的顺序检索数据。单击“提取数据”按钮后,转到控制台并进行查看
希望这就是您想要的。我相信您会面临这个问题,因为fetch hook的实现很差,而且这个示例太简单,我们无法理解。您应该清楚地说明是否将job、collegues和person放在同一个组件中。如果是这样的话,它就是
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>
);
const { loading, error, value } = useResource<Person>(getPerson, personId)