从 reducer 向用户发送错误信息

Sending error message from reducer to user

我是 React 和 Redux 的新手,我正在尝试编写一个简单的应用程序,人们可以在其中提交 URL 图像,它会显示在页面上。请注意,应用程序目前还没有后端。

export const addImage = (url) => {
    return {
        type: ADD_IMAGE,
        key: Guid.create().toString(),
        payload: url
    }
}

添加图像会创建一个类型为 ADD_IMAGE 的操作,我的减速器会相应地更新状态。但是我也检查 URL 是否已经在列表中。

switch (action.type) {
    case ADD_IMAGE:
    if (state.find(image => image.url === action.payload)) {
        return state;
    } else {
        return(
            [
                ...state,
                {key: action.key, url: action.payload}
            ]
        );
    }
    break;
    default:
}

问题是,当我拒绝 post 因为 URL 已经处于状态时,我还想通过在 div 中显示它来向用户传达该消息在表格旁边。从我读过的内容来看,我认为我不应该尝试从 reducer 访问 React 状态(如果可能的话)并且......好吧......我只是被困住了。我一直在努力寻找有关如何执行此操作的简单指南,但我找不到任何我能完全理解的东西。添加数据库后,我想我必须将其作为异步过程的一部分来执行,但正如我现在所拥有的那样,我想应该有某种简单的解决方案。

您开始将逻辑引入到您的 reducer 中,这将不可避免地导致您需要在 reducer 范围之外处理某些状态的情况。

解决方案是使用 redux-thunk(或类似的包)等中间件包将你的 reducer 逻辑转移到 thunk。这允许您将特殊类型的操作视为函数,这意味着您可以使用特定的 action-related 逻辑扩展普通操作。您给出的需要在某些条件下分派错误操作的示例对于 redux-thunk.

来说是一个很好的 use-case

下面是一个示例,说明如何将逻辑从 reducer 中提取到 thunk 中。您应该注意到,与 reducer 不同,thunk 明确支持通过 getStatedispatch 函数获取状态和分派后续操作。

Thunk 示例

export const addImage = (url) => {
  return (dispatch, getState) => {
    const key = Guid.create().toString()
    dispatch({
      type: ADD_IMAGE,
      key,
      payload: url
    })
    const state = getState()

    // you would want to use a `selector` here to locate the existing image
    // within the state tree 

    const exists = selectors.images.exists(state, url)

    if (exists) {
      dispatch(actions.ERROR_IMAGE_EXISTS({key, url}))
    }
  }
}

选择器注意事项

您会看到我正在使用 selector 来确定图像是否存在。就像 thunks 是放置调度逻辑的地方一样,selector 是放置 state-traversal 逻辑的地方。它们用于 state-tree 的 return 部分或提供简单的 state-utilities ,例如上面显示的 exists 功能。软件包可提供帮助,例如 reselect.

关注评论中的问题

  1. 选择器不是 Redux 中的 built-in 东西吗?

    不,他们不是。选择器是建立在 redux 之上的一个想法,这个概念作为放置状态搜索、缓存、读取逻辑的地方而存在。这将有时复杂的状态遍历逻辑从您的 thunk 和组件中提取出来,并放入一个非常整洁、结构化的 collection 选择器中。

  2. 为什么要使用选择器而不是 state.images.find(i => i.url === url)

    如果您使用选择器包,那么您获得的好处远不止良好的关注点分离,您还可以获得很大的性能改进(请参阅下面的使用示例)。

    以下是热门 reselect 软件包的标题:

    • 选择器可以计算派生数据,允许 Redux 存储最小可能状态。
    • 选择器是高效的。选择器不会重新计算,除非它的参数之一发生变化。
    • 选择器是可组合的。它们可以用作其他选择器的输入。
  3. 为什么 actions.ERROR_IMAGE_EXISTS(url) 对我不起作用

    因为我只是为这个例子弥补了这一点。关键是您可以从 thunk 内部调度操作,您如何声明或访问操作取决于您。我倾向于将我所有的共享操作集中到一个 actions object 中,我 import.

选择器使用示例

这是我的 real-life 代码中的一个示例,展示了我如何使用选择器将状态的一部分作为 props 传递给 React 组件:

const mapStateToProps = (state) => ({
  model: services.model.selector.getSelected(state),
  build: services.build.selector.getLastBuild(state),
  recommendations: services.recommend.selector.getRecommendations(state)
})

这些选择器中的每一个都在寻找状态树的正确部分并将其返回以备使用。漂亮整洁,如果你使用 reselector,效率很高。