如何在 saga 异步请求后设置状态
Posted
技术标签:
【中文标题】如何在 saga 异步请求后设置状态【英文标题】:how to setstate after saga async request 【发布时间】:2018-05-05 17:41:53 【问题描述】:我在我的项目中使用 redux-saga。 我以前用过 redux-thunk,所以我不能 setState 结束一些异步请求。喜欢
this.props.thunkAsync()
.then()
this.setState( '' );
由于 thunk 返回承诺,我可以使用 'then'。 但我不能用 saga 做到这一点,因为 saga 不会返回承诺。 所以我通过检查标志道具(如 REQUEST_SUCCESS、REQUEST_WAITING...)在 componentWillReceiveProps 中进行了更改。 我认为这不是解决这个问题的好方法。
所以.. 我的问题是,当异步请求以 redux-saga 结束时,我该如何做一些工作!
【问题讨论】:
你可以把 react 的 state 设置为 redux state,这样你就可以在 saga 本身中设置 state,并在这个组件中使用 redux state。 我想到了..谢谢!但是如果我想调用一些只能在本地工作的函数呢? 如果你使用 redux 来管理状态,那么你可以触发一个动作并在你的 reducer 中处理它来设置状态。 @godsenal 如果可以的话,您很可能应该将这些功能移至 saga。 @AnandS 谢谢!但是如果我想在异步请求结束后更改内联样式怎么办?我应该将此样式对象(或某些局部变量)移动到我的 redux 状态吗? 【参考方案1】:但我不能用 saga 做这个,因为 saga 不返回承诺
Redux-saga
与 thunk
略有不同,因为它是流程管理器,而不是简单的中间件:thunk
仅对触发的操作执行反应,但 saga
有自己的“流程”(正式回调刻度域)和可以通过效果来操作。
使用redux-saga
执行异步操作的通常方法是将原始操作拆分为ACTION_REQUEST
、ACTION_SUCCESS
和ACTION_FAILURE
变体。然后 reducer 只接受 SUCCESS/FAILURE 操作,并且可能对optimistic updates 进行请求。
在这种情况下,您的saga
进程可能如下所示
function* actionNameSaga(action)
try
const info = yield call(fetch, params: action.params
yield put('ACTION_NAME_SUCCESS', info)
catch(err)
yield put('ACTION_NAME_FAILURE', err)
function* rootSaga()
yield takeEvery('ACTION_NAME', actionNameSaga)
请记住,yield
操作本身与承诺等待无关 - 它只是将异步等待委托给 saga 流程管理器。
【讨论】:
【参考方案2】:您进行的每个 api 调用都作为异步请求处理,但使用 saga 中的生成器函数进行处理。
所以,在一次成功的 api 调用之后,你可以做以下可能的事情。
-
再次调用 api
function* onLogin(action) try const userName, password = action; const response = yield call(LoginService.login, userName, password); yield put(LoginService.loginSuccess(response.user.id)); const branchDetails = yield call(ProfileService.fetchBranchDetails, response.user.user_type_id); yield put(ProfileActions.fetchBranchDetailsSuccess(branchDetails)); catch (error) yield put(ProfileActions.fetchUserDetailsError(error));
api成功后传回调
onLoginClick()
const userName, password = this.state;
this.props.login(userName, password, this.onLoginSuccess);
onLoginSuccess(userDetails)
this.setState( userDetails );
function *onLogin(action)
try
const userName, password, onLoginSuccess = action;
const response = yield call(LoginService.login, userName, password);
if (onLoginSuccess)
onLoginSuccess(response);
yield put(LoginService.loginSuccess(response.user.id));
const branchDetails = yield call(ProfileService.fetchBranchDetails,
response.user.user_type_id);
yield put(ProfileActions.fetchBranchDetailsSuccess(branchDetails));
catch (error)
yield put(ProfileActions.fetchUserDetailsError(error));
更新 Reducer State 并通过 mapStateToProps 从 props 中获取
yield put(LoginService.loginSuccess(response.user.id));
@connect(
state => (
usedDetails: state.user.get('usedDetails'),
)
)
static getDerivedStateFromProps(nextProps, prevState)
const usedDetails = nextProps;
return
usedDetails
【讨论】:
【参考方案3】:你可以这样做。从组件 props 调用 saga 方法并传递成功或失败后要执行的函数,如下所示
export function* login( payload )
const url = 'localhost://login.json';
try
const response = yield call(App_Service, url, method: 'GET' );
if (response.result === 'ok' && response.data.body)
yield put(fetchDataActionCreators.getLoginSuccess(response.data.body));
//function passed as param from component, pass true if success
payload.callback(true);
catch (e)
//function passed as param from component, pass false if failure
payload.callback(false);
console.log(e);
export function* watchLogin()
while (true)
const action = yield take(LOGIN);
yield* login(action);
export default function* ()
yield all([
fork(watchLogin)
]);
在你作为参数传递给saga的函数中调用setState方法的组件
login()
// store
this.props.getServiceDetails(
callback:(success) => this.onLoginSuccess(success)
)
onLoginSuccess = (success) =>
this.setState(
login:success
)
alert('login '+success)
【讨论】:
【参考方案4】:我遇到了同样的问题...
我的解决方案是将调度包装在一个承诺中,并在一个传奇函数中调用解析和拒绝......
我创建了一个挂钩来包装调度。你可以在这里看到我的例子: https://github.com/ricardocanelas/redux-saga-promise-example
希望对大家有所帮助。
【讨论】:
以上是关于如何在 saga 异步请求后设置状态的主要内容,如果未能解决你的问题,请参考以下文章
redux-saga的简单使用——saga的模块化拆分——saga进行网络请求——同步修改状态
redux-saga的简单使用——saga的模块化拆分——saga进行网络请求——同步修改状态