Javascript 如何使用redux saga处理异步API调用?
最近,我们开始使用redux saga中间件来管理来自应用商店的异步API调用 以前,我们使用了基于承诺的通用操作,一旦我们可以在操作本身上使用Javascript 如何使用redux saga处理异步API调用?,javascript,reactjs,asynchronous,redux,redux-saga,Javascript,Reactjs,Asynchronous,Redux,Redux Saga,最近,我们开始使用redux saga中间件来管理来自应用商店的异步API调用 以前,我们使用了基于承诺的通用操作,一旦我们可以在操作本身上使用async/await和.then()和.catch()就可以轻松地管理组件流 承诺: const fetchCars = async () => { const {data} = await fetchCarsRequest(); setCars(data); } cars.map((car) => <li>{c
async/await
和.then()
和.catch()
就可以轻松地管理组件流
承诺:
const fetchCars = async () => {
const {data} = await fetchCarsRequest();
setCars(data);
}
cars.map((car) => <li>{car.name}</li>);
const fetchCars=async()=>{
const{data}=wait fetchCarsRequest();
setCars(数据);
}
cars.map((car)=>{car.name} );
关于传奇故事:
function* fetchCarsSaga() {
try {
const {data} = yield call(fetchCarsService);
yield put(fetchCarsSuccess);
} catch(error) {
yield put(fetchCarsFailure);
}
}
const fetchCars = async () => {
fetchCarsRequest(); //action that calls the above saga
setCars(cars); //state from store
}
cars.map((car) => <li>{car.name}</li>);
函数*fetchCarsSaga(){
试一试{
const{data}=产生调用(fetchCarsService);
收益率看跌期权(FetchCarsAccess);
}捕获(错误){
收益率看跌期权(FETCHARSFAILURE);
}
}
const fetchCars=async()=>{
fetchCarsRequest();//调用上述事件的操作
setCars(cars);//从商店中声明
}
cars.map((car)=>{car.name} );
在第二个示例中,即使我们使用生成器来处理异步API调用,也不可能使用wait
语句,因此它在调用fetchCarsRequest
之后立即调用setCars
函数,试图将尚不存在的内容设置为组件状态
因此,我的问题是:有没有一种方法可以替换
await
语句,然后等待请求函数(这不是异步函数)完成API调用?使用redux saga,流程会有所不同。您不能在组件中直接使用生成器。您需要从saga中更新redux状态,并在组件中获取它
react component -> redux action -> saga -> redux state -> react component
PT-BR中的两篇文章是:
create react app
模板是:
fetchCarsRequest()
,该操作将触发API调用并将结果保存到redux存储中。您需要等待此操作完成,然后调用setCars(cars)
将组件状态设置为redux状态的值。为什么?
这是一种反模式。数据已经存在于redux中,应该直接从组件中的redux访问。您应该使用use selector
或connect
HOC从redux选择cars
的值。一旦您的fetch已调度fetchcarssaccess
并更新了存储状态,它将自动使用新数据重新呈现组件
应该是这样的
传奇
组成部分
const Cars = () => {
const dispatch = useDispatch();
const cars = useSelector( state => state.cars.data ) || [];
const isLoading = useSelector( state => state.cars.isLoading );
const error = useSelector( state => state.cars.error );
useEffect( () => {
dispatch(fetchCarsRequest()); // action that calls the saga
}, [] );
return (
{!! error && (<div>Error: {error}</div>)}
{isLoading ? <Spinner/> : (
<ul>
{cars.map((car) => <li key={car.id}>{car.name}</li>)}
</ul>
)}
)
}
const Cars=()=>{
const dispatch=usedpatch();
const cars=useSelector(state=>state.cars.data)| |[];
const isLoading=useSelector(state=>state.cars.isLoading);
const error=useSelector(state=>state.cars.error);
useffect(()=>{
dispatch(fetchCarsRequest());//调用传奇的操作
}, [] );
返回(
{!!错误&(错误:{error})}
{正在加载?:(
{cars.map((car)=>- {car.name}
)}
)}
)
}
不清楚您到底在问什么-您使用的名称与代码中的函数/生成器名称不完全匹配这一事实没有帮助。但是redux saga的调用
将自动“等待”一个承诺,如果被调用的函数返回一个承诺-就像所有异步
函数一样。如果在调用fetchCarsRequest
之前放置wait
(因此该函数隐式返回的承诺直到fetchCarsRequest
解决后才会解决),那么我认为一切都应该正常工作?我想我无法很好地表达自己。我的主要疑问是,一旦saga处理异步调用,如何等待API调用完成,而不使用wait
,调用另一个函数。例如,我想等待saga完成API调用并将状态设置为store,以打开一个成功模式。我该怎么做呢?@Gabriel在我看来useffect
是“正确”的方法,所以我不确定你为什么要做其他事情。中间件使得您可以等待调度
。我不认为redux传奇也有同样的效果,但我从未尝试过。你们完全正确。它确实解决了useffect
的问题,但仅在这种情况下。事实上,我在几乎所有一开始就必须发出API请求的组件中都这样做,我的问题是:如何等待saga完成API调用并将状态设置为存储,然后才打开一个成功模式,例如?在这种情况下,只需单击按钮即可调用请求。谢谢@oieduardorabelo的回复。这些文章真的很有用。但我的问题是:例如,如何等待saga完成API调用并将状态设置为存储,然后才打开成功模式?在这种情况下,调用该传奇的操作只需单击按钮即可调用。@GabrielSantana,您需要在redux状态下控制该操作。假设你的传奇用yield-put({type:“CAR\u-MODAL\u-OPEN”})更新redux状态
,这个动作会触发一个reducer,该reducer使用{modals:{CAR:“OPEN”}}}
返回新状态,然后在你的react组件中,你可以将这个状态映射到道具,在渲染函数中,您可以检查props.carModal===“open”
以渲染所需的任何内容。循环react component->redux action->saga->redux state->react component
是状态如何流动/更新的。是的。事实上,它确实解决了问题。但它仍然在减速器内部处理,具有全局状态,而不是在调用减速器的组件内部。也许没有一种方法像wait
那样等待。我猜在sagas中,你必须一直跟踪edux状态的变化,才能在u中做一些事情
const Cars = () => {
const dispatch = useDispatch();
const cars = useSelector( state => state.cars.data ) || [];
const isLoading = useSelector( state => state.cars.isLoading );
const error = useSelector( state => state.cars.error );
useEffect( () => {
dispatch(fetchCarsRequest()); // action that calls the saga
}, [] );
return (
{!! error && (<div>Error: {error}</div>)}
{isLoading ? <Spinner/> : (
<ul>
{cars.map((car) => <li key={car.id}>{car.name}</li>)}
</ul>
)}
)
}