首页 > 解决方案 > 像异步操作的当前状态这样的东西应该存储在 react-redux 应用程序中的什么位置?

问题描述

我有一个登录弹出窗口,它将“isLoggingIn”布尔值映射到 redux 存储。当一个登录请求动作被调度时,一个 saga 拦截该动作并发送另一个登录正在处理的动作,reducer 将接收它并将“isLoggingIn”布尔值设置为 true。

我的店铺:

export interface AppState {
  playerToken:string,  
  loginOpen: boolean,
  loginProcessing: boolean
}

登录传奇:

function* loginUser(action: any) {
  yield put({ type: (LOGIN + PROCESSING) });

  try {
    const response = yield call(apiCall, 'api/token', 'POST', { username: action.payload.username, password: action.payload.password });

   if (response) 
   {
      yield put({ type: (LOGIN + SUCCESS), payload: response.data });
  }
  catch ({ statusCode }) {
    if (statusCode === 401) {
      yield put({ type: (LOGIN + FAIL), payload: { error: "Invalid username or password" } })
    }
    console.log(statusCode);
  }
}

一旦 saga 完成登录,如果出现错误,它会调度一个 action,reducer 将其设置为 store 中的“loginError”字符串并将 isLoggingIn 设置为 false,否则 isLoggingIn 设置为 false 并设置用户登录 ID提示弹出窗口隐藏自身(即 isVisible={this.props.playerToken == undefined)。

这看起来非常复杂,但我不确定如何使用 Redux 原则来解决这个问题。我强烈认为 isProcessingLogin 应该是组件状态的一部分,但是组件在发送登录尝试事件后并不真正知道发生了什么,除非它正在侦听道具中的某些内容,否则它无法知道。

对于需要发生的各种 crud 操作以及必须在商店中设置为 true/false 并在组件中正确映射的各种“isCreatingXModel”布尔值,情况会变得更糟。

这是redux应该如何工作还是我在不属于它的地方过度使用它?

如果这就是应该如何使用 redux,那么它的好处到底是什么?我在网上读过很多关于有道理的事情,比如有一个单一的事实,但它们都可以在没有疯狂的 redux 膨胀的情况下完成,我读过人们说在你需要它之​​前不要使用 redux,但这意味着我'将在我'需要'时集成redux时在两个概念上独立的代码区域中进行api调用,最后我看到倡导者声称的最大优势之一是它能够及时倒带和前进,这是很好,但它不会在任何连接到它操作的后端数据库的实时应用程序中工作,除非作为倒带的一部分,有一个撤消最后一个 api 调用操作。

标签: javascriptreactjsreduxreact-redux

解决方案


请记住,这些完全是我的意见。

1. 您可能不需要 sagas(或 thunk 或其他“异步”redux 插件)

请记住,redux 只是状态管理。API 调用可以用 vanilla javascript 编写,带或不带 redux。例如:这是没有 sagas 的流程的基本复制:

例如

import { setLoadingStatus } from './actions'
import { store } from './reducers' // this is what is returned by a createStore call

export function myApiCall(myUrl, fetchOptions) {
  store.dispatch(setLoadingStatus('loading'))

  return fetch(myUrl, fetchOptions)
    .then((response) => {
      store.dispatch(setLoadingStatus('succeeded', data))
      // do stuff with response data (maybe dispatch a different action to use it?)
    })
    .catch((error) => {
      store.dispatch(setLoadingStatus('failed', error))
      // do stuff 
    })
}

注意使用store.dispatch. React-Redux 中有一个有趣的概念,即您只能使用 mapDispatchToProps 调度操作,但幸运的是,这不是真的。

我用一个带有状态和可选数据的操作替换了您的多个操作。这将减少您需要编写的动作和减速器的数量,但您的动作历史将更难阅读。(而不是三个不同的动作,你只会有一个。)

2. 你可能不需要 redux。

如果您不使用 redux,上面的示例函数可能看起来基本相同——想象一下用store.dispatch调用替换this.setState调用。将来,当你添加它时,你仍然需要编写所有的 reducer、action、action creator 样板文件,但这只会比从一开始就更痛苦一些。

正如我上面所说,我通常在使用 React 时使用 Redux,内置状态管理对于任何类型的大型应用程序都有一个糟糕的思维导图。

有两条相反的经验法则:

  1. 对需要在组件之间共享的状态使用 redux
  2. 对所有状态使用 redux 并获得单一的事实来源

我倾向于倾向于第二个。我讨厌在大型 React 组件树的叶子中寻找错误的状态片段。这绝对是一个没有“正确”答案的问题。


推荐阅读