【问题标题】:Redux: Reusable actionsRedux:可重用的操作
【发布时间】:2016-10-10 18:38:18
【问题描述】:

我有一个使用 redux thunk 的操作,看起来像这样:

export function fetchData(query) {
  return dispatch => {
    return fetch(`http://myapi?query=${query}` ,{mode: 'cors'})
      .then(response => response.json())
      .then(json => { dispatch(someOtherAction(json)) })
    }
  }
}

然后我的someOtherAction 实际更新状态:

export function someOtherAction(data) {
    return {
        action: types.SOME_ACTION,
        data
    }
}

但我希望fetchData 动作创建者可以重复使用,以便我的应用程序的不同部分可以从myapi 获取数据,然后基于此拥有不同的状态部分。

我想知道重用此操作的最佳方式是什么?是否可以将第二个参数传递给我的 fetchData 动作创建者,该参数规定在成功获取时调用哪个动作:

export function fetchData(query, nextAction) {
  return dispatch => {
    return fetch(`http://myapi?query=${query}` ,{mode: 'cors'})
      .then(response => response.json())
      .then(json => { dispatch(nextAction(json)) })
    }
  }
}

或者是否有一种可接受的方式来做这种事情?

【问题讨论】:

  • 看起来您无法将其他参数传递给操作。
  • 我有一些非常相似的东西一起被黑了。我还将nextErrorAction 作为fetchData 的附加参数。此外,当状态码为 2xx 和 dispatch(nextErrorAction(data))reject 时,我还返回一个承诺和 dispatch(nextAction(data)) 以及 resolve 和 4xx/5xx。它最终工作得很好,只需要几行代码。
  • 啊好吧,这很有趣。找不到任何有关您是否应该传递额外参数的文档。认为我可能根本不需要采取行动? github.com/gaearon/redux-thunk 定义了一个 fetchSecretSauce 方法,该方法在动作创建者之外进行获取。

标签: redux


【解决方案1】:

我为此使用了一个中间件。我已经在其中定义了 fetch 调用,然后在我的操作中我发送 URL 以获取,并在完成时发送操作。这将是一个典型的 fetch 操作:

const POSTS_LOAD = 'myapp/POST_L';
const POST_SUCCESS = 'myapp/POST_S';
const POST_FAIL = 'myapp/POST_F';

export function fetchLatestPosts(page) {
  return {
    actions: [POSTS_LOAD, POST_SUCCESS, POST_FAIL],
    promise: {
      url: '/some/path/to/posts',
      params: { ... },
      headers: { ... },
    },
  };
}

当调用该操作时,POST_LOAD 操作将在执行获取请求之前由中间件自动分派。如果一切顺利,POST_SUCCESS 动作将与 json 响应一起调度,如果出现问题,POST_FAIL 动作将由中间件调度。

它在中间件中的所有魔力!它与此类似:

export default function fetchMiddleware() {
  return ({ dispatch, getState }) => {
    return next => action => {
      if (typeof action === 'function') {
        return action(dispatch, getState);
      }

      const { promise, actions, ...rest } = action;

      if (!promise) {
        return next(action);
      }

      const [REQUEST, SUCCESS, FAILURE] = actions;
      next({ ...rest, type: REQUEST }); // <-- dispatch the LOAD action


      const actionPromise = fetch(promise.url, promise); // <-- Make sure to add the domain

      actionPromise
        .then(response => response.json())
        .then(json => next({ ...rest, json, type: SUCCESS })) // <-- Dispatch the success action
        .catch(error => next({ ...rest, error, type: FAILURE })); // <-- Dispatch the failure action

      return actionPromise;
    };
  };
}

这样,我将所有请求放在一个地方,我可以定义在请求完成后要运行的操作。

------------编辑----

为了获取reducer上的数据,你需要使用你在原始action creator上定义的action名称。以下示例展示了如何处理来自中间件的POST_SUCCESS 操作以从json 响应中获取posts 数据。

export function reducer(state = {}, action) {
  switch(action.type) {
    case POST_SUCCESS:  // <-- Action name
      return {
        ...state,
        posts: action.json.posts, // <-- Getting the data from the action
      }
    default:
      return state;
  }
}

我希望这会有所帮助!

【讨论】:

  • 感谢@crysfel 的回答。一个问题。什么是 POST_LOAD、POST_SUCCESS?它是一个动作创建函数还是一个具有类型和动作的对象。你有没有机会添加一个例子来说明那里的动作?
  • 这只是动作名称:const POSTS_LOAD = 'myapp/POST_L'; 你将在减速器上收到这个。根据这个名称,您可以对数据或状态做任何您想做的事情。我添加了一个减速器的例子。
  • 道歉,忽略前面。我的代码中有一个愚蠢的错误。非常感谢您的帮助。我在这里学到了很多东西,现在也能快速创建自己的 redux 中间件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-23
  • 2016-12-15
  • 2020-02-25
  • 2018-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多