Reactjs 从一个redux传奇中调用两种不同的动作类型
我现在已经能够通过基本的sagas实现了,但是我的应用程序变得有点复杂了。我选择sagas作为异步功能,但似乎误解了事情的工作原理 我的应用程序中有一个全局搜索输入,需要进行两个不同的api调用(不同的数据对象),但搜索输入也有自己的加载状态,具体取决于api调用的搜索/状态。基于此信息,这是应用程序的流程:Reactjs 从一个redux传奇中调用两种不同的动作类型,reactjs,redux,redux-saga,Reactjs,Redux,Redux Saga,我现在已经能够通过基本的sagas实现了,但是我的应用程序变得有点复杂了。我选择sagas作为异步功能,但似乎误解了事情的工作原理 我的应用程序中有一个全局搜索输入,需要进行两个不同的api调用(不同的数据对象),但搜索输入也有自己的加载状态,具体取决于api调用的搜索/状态。基于此信息,这是应用程序的流程: 搜索发生(发送操作全局搜索请求) GLOBAL\u SEARCH\u REQUEST的saga watcher启动(将输入的加载设置为true) 在这个故事中-调用以获取与搜索查询匹配的所
全局搜索请求)
GLOBAL\u SEARCH\u REQUEST
的saga watcher启动(将输入的加载设置为true)function* globalSearchRequestSaga(action) {
const { query } = action
console.log(`searching subscriptions and users for : ${query}`)
try {
yield put(fetchUsersRequest(query))
// call for the subscriptions (leaving it out for simplicity in this example)
yield put(globalSearchSuccess(query))
} catch (error) {
console.log(`error: ${error}`)
yield put(globalSearchFailure(error.message))
}
}
fetch users传奇看起来像什么
export function* fetchUsersRequestSaga(action) {
const { query } = action
const path = `${root}/users`
try {
const users = yield axios.get(path, { crossDomain: true })
yield put(fetchUsersSuccess(query, users.data))
} catch (error) {
console.log(`error : ${error}`)
yield put(fetchUsersFailure(query, error.message))
}
}
(非常基本)
如果我这样做,就会出现一个问题,GLOBAL\u SEARCH\u SUCCESS
操作在用户请求完成之前执行(如果我也在订阅api调用中添加了此操作,我会想到同样的问题)。我找到的一个解决办法是,如果我改变路线
yield put(fetchUsersRequest(query))
到
其中,fetchUsersRequestSaga
是上面的saga,而fetchUsersRequest(query)
是获取用户的操作创建者。这会导致asnyc功能正常工作,并等待用户返回(正确行为)
唯一的问题是,FETCH\u USERS\u请求
操作不再记录到存储中
我想知道是否有一种方法可以让它正确地登录到存储,或者返回到我以前的实现,并在
put(fetchUsersRequest(query))
上进行适当的阻塞put
函数是一种非阻塞操作。它不会等到promise/api请求得到解决
我建议你直接给萨加斯打电话,而不是采取行动
try {
yield call(fetchUsersRequestSaga, query);
yield call(globalSearchSaga, query); // or whatever its called
}
调用
是一种阻塞操作。它将一直等到请求完成,因此无论您的调用是否按正确的顺序执行。我使用sagas已经有一段时间了,但下面的一些代码将让您大致了解如何等待已调度的操作
它的工作方式是,当您获取并希望等待它失败或成功时,为获取操作提供一个id,然后您可以将该id传递给waitFor函数,同时分派该操作
如果您不想或不需要等待它,那么您可以在没有id的情况下发送操作,它仍然可以工作:
const addId = (id => fn => (...args) => ({
...fn(...args),
id: id++,
}))(0);
const withId = ({ id }, action) => ({ action, id });
function* waitFor(id) {
const action = yield take('*');
if (action.id === id) {
return action;
}
return waitFor(id);
}
function* globalSearchRequestSaga(action) {
const { query } = action;
console.log(
`searching subscriptions and users for : ${query}`
);
try {
//add id to action (id is unique)
const action = addId(fetchUsersRequest, query);
//dispatch the action and then wait for resulting action
// with the same id
yield put(action);
const result = yield waitFor(action.id);
// call for the subscriptions (leaving it out for simplicity in this example)
yield put(globalSearchSuccess(query));
} catch (error) {
console.log(`error: ${error}`);
yield put(globalSearchFailure(error.message));
}
}
export function* fetchUsersRequestSaga(action) {
const { query } = action;
const path = `${root}/users`;
try {
const users = yield axios.get(path, {
crossDomain: true,
});
yield put(//add original id to success action
withId(action, fetchUsersSuccess(query, users.data))
);
} catch (error) {
console.log(`error : ${error}`);
yield put(
withId(//add original id to fail action
action,
fetchUsersFailure(query, error.message)
)
);
}
}
您可以生成一个关于获取用户的成功或失败,但由于您放置了多个获取用户操作,因此您必须等待您刚刚触发的准确的成功或失败,这意味着为您的获取用户操作提供一个id,并让成功和失败使用该id。因此,您在
fetchUsersRequestSaga
doyield-take中这样说(FetchUsersAccess(query,users.data)
这会阻止另一个传奇中globalSearchSuccess()
的执行吗?我添加了一个答案,让我知道这是否有效。不久前在一个通用api层中做了类似的事情,因此可能错过了一些收益(可能waitFor需要返回收益waitFor(id))
当它递归调用自身时。OP已尝试调用,但未调度fetch user,且从未调用fetch user的减缩器。@HMR那么为什么不将“fetch user逻辑”移动到saga中?或者只在saga中调度它,但断开globalSearchRequestSaga
从侦听该操作的连接。在哪里他的名字是从哪里来的?是的!因为我正在处理两个传奇,用户和搜索,你说在这次尝试中调用这两个传奇(我想我会从searchSaga
中调用他们)@erp您必须在globalSearchRequestSaga
中给他们打电话,就像您在上面做的那样。但是打电话而不是采取行动。谢谢您的回复。我需要一些时间来查看this@erp我编辑了答案,我认为它是yieldall([put(action),call(waitFor(action.id)));
如果要分派一个获取操作并等待另一个id相同的操作(成功或失败)。可能产生put(操作);yied调用(waitFor(action.id)))
也可以,但我不确定。我认为这可能有点过于复杂了problem@erp查看了旧代码并更新了答案,您可以调度fetch操作,然后执行const result yield waitFor(刚刚调度的操作的id)
,结果将是fetch saga将分派的成功或失败操作。
const addId = (id => fn => (...args) => ({
...fn(...args),
id: id++,
}))(0);
const withId = ({ id }, action) => ({ action, id });
function* waitFor(id) {
const action = yield take('*');
if (action.id === id) {
return action;
}
return waitFor(id);
}
function* globalSearchRequestSaga(action) {
const { query } = action;
console.log(
`searching subscriptions and users for : ${query}`
);
try {
//add id to action (id is unique)
const action = addId(fetchUsersRequest, query);
//dispatch the action and then wait for resulting action
// with the same id
yield put(action);
const result = yield waitFor(action.id);
// call for the subscriptions (leaving it out for simplicity in this example)
yield put(globalSearchSuccess(query));
} catch (error) {
console.log(`error: ${error}`);
yield put(globalSearchFailure(error.message));
}
}
export function* fetchUsersRequestSaga(action) {
const { query } = action;
const path = `${root}/users`;
try {
const users = yield axios.get(path, {
crossDomain: true,
});
yield put(//add original id to success action
withId(action, fetchUsersSuccess(query, users.data))
);
} catch (error) {
console.log(`error : ${error}`);
yield put(
withId(//add original id to fail action
action,
fetchUsersFailure(query, error.message)
)
);
}
}