@actualwave/redux-create-reducer 中文文档教程

发布于 6年前 浏览 8 更新于 3年前

@actualwave/redux-create-reducer

这个包包含两个用于创建 redux reducer 函数的函数 来自较小的每次操作函数。 所以

import {
  FETCH_DATA_SUCCESS,
  FETCH_DATA_FAILURE,
  UPDATE_DATA_SUCCESS,
  UPDATE_DATA_FAILURE,
  DELETE_DATA_SUCCESS,
  DELETE_DATA_FAILURE,
} from './actions';

const initialState = {};

const reducer = (state = initialState, action) => {
  switch(action.type) {
    case FETCH_DATA_SUCCESS:
      ...
    break;
    case FETCH_DATA_FAILURE:
     ...
    break;
    case UPDATE_DATA_SUCCESS:
      ...
    break;
    case UPDATE_DATA_FAILURE:
     ...
    break;
    case DELETE_DATA_SUCCESS:
      ...
    break;
    case DELETE_DATA_FAILURE:
     ...
    break;
  }
}

export default reducer;

你可能有这个结构

const getInitialState = () => ({});

export const fetchDataSuccess = (state, action) => {
  ...
};

export const fetchDataFailure = (state, action) => {
  ...
};

export const updateDataSuccess = (state, action) => {
  ...
};

export const updateDataFailure = (state, action) => {
  ...
};

export const deleteDataSuccess = (state, action) => {
  ...
};

export const deleteDataFailure = (state, action) => {
  ...
};

export default getInitialState;

Install

使用 NPM

npm install @actualwave/redux-create-reducer

Yarn

yarn add @actualwave/redux-create-reducer

或从 original gist 下载源代码。

How to use

例如,我们在设置文件中有 actions、reducer 和 redux 配置三个文件。

  1. Define action types in actions file
export const FETCH_SETTINGS_SUCCESS = 'fetchSettingsSuccess';

action type 的值将用于确定应调用哪个函数。

  1. Use action type to create a reducer function for it in reducer file
export const fetchSettingsSuccess = (state, { payload }) => ({
  ...state,
  ...payload,
  initialized: true,
});
  1. If default export from reducer file exists, it must be a factory function for default state. If not defined, function that always returns empty object will be used. So, let's add default state factory to reducer file
export default () => {
  return {
    firstSetting: true,
    secondSetting: false,
    initialized: false,
  };
};
  1. Add reducer to redux storage in setup file
import { createStore, combineReducers } from 'redux';
import { createReducer } from '@actualwave/redux-create-reducer';
import * as settings from './reducer';

const store = createStore(
  combineReducers({
    settings: createReducer(settings),
  }),
);

如果你有多个 reducer

import { createStore, combineReducers } from 'redux';
import { createReducers } from '@actualwave/redux-create-reducer';
import * as items from './items/reducer';
import * as settings from './settings/reducer';
import * as users from './users/reducer';

const store = createStore(
  combineReducers(
    createReducers({
      items,
      settings,
      users,
    }),
  ),
);

API

这个模块公开了两个函数

  • createReducer() -- create reducer function from an object with set of action handlers. Each action handler is assigned to action type by property key and will be called only when action of this type passed.
/*
  Will create a reducer function which accept "fetchDataSuccess" and "fetchDataFailure" actions.
*/
const reducer = createReducer({

  /*
    this function will be called only when action with type "fetchDataSuccess" is dispatched:
    { type: "fetchDataSuccess" }
  */
  fetchDataSuccess: (state, action) => ...,

  /*
    this function will be called only when action with type "fetchDataFailure" is dispatched:
    { type: "fetchDataFailure" }
  */
  fetchDataFailure: (state, action) => ...,
});
/*
  Will create a reducer function which accept "fetchDataSuccess" and "fetchDataFailure" actions
  and have empty `items` array in default state object.
*/
const reducer = createReducer({

  // handles "fetchDataSuccess" actions
  fetchDataSuccess: (state, action) => ...,

  // handles "fetchDataFailure" actions
  fetchDataFailure: (state, action) => ...,

  // default state factory
  default: () => ({items: []}),
});

通常它用于从一个描述单个 reducer 的文件中导出 从一个

/*
  contents of ./data/reducer file

  Every exported entity must be an action handling function and
  `export default` must be a default state factory.
*/

// handles "fetchDataSuccess" actions
export const fetchDataSuccess: (state, action) => ...;

// handles "fetchDataFailure" actions
export const fetchDataFailure: (state, action) => ...;

// default state factory
export default () => ({items: []});

reducer 文件中导入所有内容并从中创建一个 reducer 函数。

import * data from './data/reducer';

const reducer = createReducer(data);
  • createReducers() -- applies createReducer() to object properties.
// create reducers for "data", "settings" and "items" properties
const reducers = createReducers({
  data,
  settings,
  items,
});

等效于

const reducers = {
  data: createReducer(data),
  settings: createReducer(settings),
  items: createReducer(items),
});

接受对象的对象并返回具有相同键但缩减器函数作为值的对象。

const reducers = createReducers({
  data: {
    fetchDataSuccess: (state, action) => ...,
    fetchDataFailure: (state, action) => ...,
    default: () => ({ items: [] }),
  },
});

此代码将导致为“fetchDataSuccess”和“fetchDataFailure”操作创建一个缩减程序,这些操作将存储在“data”属性中:

{
  data: (state, action) => {
    /* "fetchDataSuccess" and "fetchDataFailure" handled here */
    ...
  },
};

然后可以将此对象直接传递给 redux 的 combineReducers()

const reducers = combineReducers(
  createReducers({
    data: {
      fetchDataSuccess: (state, action) => ({ ...state, loaded: true }),
      fetchDataFailure: (state, action) => ({ ...state, loaded: false }),
      default: () => ({ items: [], loaded: false }),
    },
  })
);

Notes

根据我的经验,createReducer() 最适用于驼峰式操作类型

// good
const MY_FIRST_ACTION = 'myFirstAction';

// bad
const MY_SECOND_ACTION = 'MY_SECOND_ACTION';

。在这种情况下,您将在 reducer 文件中获得操作处理程序的这些函数名称:

// for "myFirstAction" action type
export const myFirstAction = (state, action) => {
  ...
};

// for "MY_SECOND_ACTION" action type
export const MY_SECOND_ACTION = (state, action) => {
  ...
};

但这完全取决于开发人员如何生成操作类型,他们只需要是有效的 JS 标识符。

如果您喜欢这种构造 reducer 的方式,请检查 redux-actions 库,它提供了用于管理操作的复杂和标准化方法的工具和减速机。

@actualwave/redux-create-reducer

This package contains two functions made to create a redux reducer function from smaller per-action functions. So instead of

import {
  FETCH_DATA_SUCCESS,
  FETCH_DATA_FAILURE,
  UPDATE_DATA_SUCCESS,
  UPDATE_DATA_FAILURE,
  DELETE_DATA_SUCCESS,
  DELETE_DATA_FAILURE,
} from './actions';

const initialState = {};

const reducer = (state = initialState, action) => {
  switch(action.type) {
    case FETCH_DATA_SUCCESS:
      ...
    break;
    case FETCH_DATA_FAILURE:
     ...
    break;
    case UPDATE_DATA_SUCCESS:
      ...
    break;
    case UPDATE_DATA_FAILURE:
     ...
    break;
    case DELETE_DATA_SUCCESS:
      ...
    break;
    case DELETE_DATA_FAILURE:
     ...
    break;
  }
}

export default reducer;

You may have this structure

const getInitialState = () => ({});

export const fetchDataSuccess = (state, action) => {
  ...
};

export const fetchDataFailure = (state, action) => {
  ...
};

export const updateDataSuccess = (state, action) => {
  ...
};

export const updateDataFailure = (state, action) => {
  ...
};

export const deleteDataSuccess = (state, action) => {
  ...
};

export const deleteDataFailure = (state, action) => {
  ...
};

export default getInitialState;

Install

Use NPM

npm install @actualwave/redux-create-reducer

Yarn

yarn add @actualwave/redux-create-reducer

Or download source from original gist.

How to use

For example, we have three files for actions, reducer and redux configuration in setup file.

  1. Define action types in actions file
export const FETCH_SETTINGS_SUCCESS = 'fetchSettingsSuccess';

The value of action type will be used to determine which function should be called.

  1. Use action type to create a reducer function for it in reducer file
export const fetchSettingsSuccess = (state, { payload }) => ({
  ...state,
  ...payload,
  initialized: true,
});
  1. If default export from reducer file exists, it must be a factory function for default state. If not defined, function that always returns empty object will be used. So, let's add default state factory to reducer file
export default () => {
  return {
    firstSetting: true,
    secondSetting: false,
    initialized: false,
  };
};
  1. Add reducer to redux storage in setup file
import { createStore, combineReducers } from 'redux';
import { createReducer } from '@actualwave/redux-create-reducer';
import * as settings from './reducer';

const store = createStore(
  combineReducers({
    settings: createReducer(settings),
  }),
);

If you have multiple reducers

import { createStore, combineReducers } from 'redux';
import { createReducers } from '@actualwave/redux-create-reducer';
import * as items from './items/reducer';
import * as settings from './settings/reducer';
import * as users from './users/reducer';

const store = createStore(
  combineReducers(
    createReducers({
      items,
      settings,
      users,
    }),
  ),
);

API

This module exposes two functions

  • createReducer() -- create reducer function from an object with set of action handlers. Each action handler is assigned to action type by property key and will be called only when action of this type passed.
/*
  Will create a reducer function which accept "fetchDataSuccess" and "fetchDataFailure" actions.
*/
const reducer = createReducer({

  /*
    this function will be called only when action with type "fetchDataSuccess" is dispatched:
    { type: "fetchDataSuccess" }
  */
  fetchDataSuccess: (state, action) => ...,

  /*
    this function will be called only when action with type "fetchDataFailure" is dispatched:
    { type: "fetchDataFailure" }
  */
  fetchDataFailure: (state, action) => ...,
});
/*
  Will create a reducer function which accept "fetchDataSuccess" and "fetchDataFailure" actions
  and have empty `items` array in default state object.
*/
const reducer = createReducer({

  // handles "fetchDataSuccess" actions
  fetchDataSuccess: (state, action) => ...,

  // handles "fetchDataFailure" actions
  fetchDataFailure: (state, action) => ...,

  // default state factory
  default: () => ({items: []}),
});

Normally its used against exports from one file that describes single reducer

/*
  contents of ./data/reducer file

  Every exported entity must be an action handling function and
  `export default` must be a default state factory.
*/

// handles "fetchDataSuccess" actions
export const fetchDataSuccess: (state, action) => ...;

// handles "fetchDataFailure" actions
export const fetchDataFailure: (state, action) => ...;

// default state factory
export default () => ({items: []});

Import everything from a reducer file and create a reducer function from it.

import * data from './data/reducer';

const reducer = createReducer(data);
  • createReducers() -- applies createReducer() to object properties.
// create reducers for "data", "settings" and "items" properties
const reducers = createReducers({
  data,
  settings,
  items,
});

Is equivalent to

const reducers = {
  data: createReducer(data),
  settings: createReducer(settings),
  items: createReducer(items),
});

Accepts object of objects and returns object with same keys but reducer functions as values.

const reducers = createReducers({
  data: {
    fetchDataSuccess: (state, action) => ...,
    fetchDataFailure: (state, action) => ...,
    default: () => ({ items: [] }),
  },
});

This code will result in creating a reducer for "fetchDataSuccess" and "fetchDataFailure" actions which will be stored in "data" property:

{
  data: (state, action) => {
    /* "fetchDataSuccess" and "fetchDataFailure" handled here */
    ...
  },
};

Then this object can be passed directly to redux's combineReducers().

const reducers = combineReducers(
  createReducers({
    data: {
      fetchDataSuccess: (state, action) => ({ ...state, loaded: true }),
      fetchDataFailure: (state, action) => ({ ...state, loaded: false }),
      default: () => ({ items: [], loaded: false }),
    },
  })
);

Notes

From my experience, createReducer() best works with camel-cased action types

// good
const MY_FIRST_ACTION = 'myFirstAction';

// bad
const MY_SECOND_ACTION = 'MY_SECOND_ACTION';

In this case you will get these function names for action handlers in reducer file:

// for "myFirstAction" action type
export const myFirstAction = (state, action) => {
  ...
};

// for "MY_SECOND_ACTION" action type
export const MY_SECOND_ACTION = (state, action) => {
  ...
};

But its all up to developer how to generate action types, they just need to be valid JS identifiers.

If you like such way of structuring reducers, check redux-actions library, it gives tools for complex and standartized approach for managing actions and reducers.

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文