@acemarke/redux-starter-kit 中文文档教程

发布于 6年前 浏览 19 项目主页 更新于 3年前

redux-starter-kit

npm versionnpm downloads

一组简单的工具,使使用 Redux 更容易

npm install @acemarke/redux -starter-kit

Purpose

redux-starter-kit 包旨在帮助解决关于 Redux 的三个常见抱怨:

  • "Configuring a Redux store is too complicated"
  • "I have to add a lot of packages to get Redux to do anything useful"
  • "Redux requires too much boilerplate code"

我们无法解决所有用例,但本着 create-react-appapollo-boost,我们可以尝试提供一些工具来抽象设置过程并处理最常见的使用案例,以及一些有用的实用程序,可以让用户简化他们的应用程序代码。

这个包不是旨在解决关于 Redux 的每一个可能的投诉,并且故意限制在范围内。 它解决诸如“可重用封装的 Redux 模块”、数据获取、文件夹或文件结构、管理商店中的实体关系等概念。

What's Included

redux-starter-kit 包括:

  • A configureStore() function with simplified configuration options. It can automatically combine your slice reducers, adds whatever Redux middleware you supply, includes redux-thunk by default, and enables use of the Redux DevTools Extension.
  • A createReducer() utility that lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses the immer library to let you write simpler immutable updates with normal mutative code, like state.todos[3].completed = true.
  • An improved version of the widely used createSelector utility for creating memoized selector functions, which can accept string keypaths as "input selectors" (re-exported from the selectorator library).

API Reference

configureStore

对标准 Redux createStore 函数的更友好的抽象。 采用单个配置对象参数,具有以下选项:

function configureStore({
    // A single reducer function that will be used as the root reducer,
    // or an object of slice reducers that will be passed to combineReducers()
    reducer: Object<string, Function> | Function,
    // An array of Redux middlewares.  If not supplied, defaults to just redux-thunk.
    middleware: Array<MiddlewareFunction>,
    // Built-in support for devtools. Defaults to true.
    devTools: boolean,
    // Same as current createStore.
    preloadedState : State,
    // Same as current createStore.
    enhancer : ReduxStoreEnhancer,
})

基本用法:

import { configureStore } from '@acemarke/redux-starter-kit'

import rootReducer from './reducers'

const store = configureStore({ reducer: rootReducer })
// The store now has redux-thunk added and the Redux DevTools Extension is turned on

完整示例:

import {
  configureStore,
  getDefaultMiddleware
} from '@acemarke/redux-starter-kit'

// We'll use redux-logger just as an example of adding another middleware
import logger from 'redux-logger'

// And use redux-batch as an example of adding enhancers
import { reduxBatch } from '@manaflair/redux-batch'

import todosReducer from './todos/todosReducer'
import visibilityReducer from './visibility/visibilityReducer'

const reducer = {
  todos: todosReducer,
  visibility: visibilityReducer
}

const middleware = [...getDefaultMiddleware(), logger]

const preloadedState = {
  todos: [
    {
      text: 'Eat food',
      completed: true
    },
    {
      text: 'Exercise',
      completed: false
    }
  ],
  visibilityFilter: 'SHOW_COMPLETED'
}

const store = configureStore({
  reducer,
  middleware,
  devTools: NODE_ENV !== 'production',
  preloadedState,
  enhancers: [reduxBatch]
})

// The store has been created with these options:
// - The slice reducers were automatically passed to combineReducers()
// - redux-thunk and redux-logger were added as middleware
// - The Redux DevTools Extension is disabled for production
// - The middleware, batch, and devtools enhancers were automatically composed together

getDefaultMiddleware

如果您需要在不删除 redux-starter-kit 的默认中间件的情况下添加自定义中间件,则 getDefaultMiddleware 很有用。 目前它返回一个带有 redux-thunk 的数组。

createReducer

用于创建处理特定操作类型的 reducer 的实用函数,类似于 "Reducing Boilerplate" Redux 中的示例函数文档页面。 获取一个初始状态值和一个将操作类型映射到 case reducer 函数的对象。 在内部,它使用 immer,因此您可以在您的 case reducer 中编写代码来改变现有的state 值,它将正确地生成不可变更新的状态值。

function createReducer(
  initialState: State,
  actionsMap: Object<String, Function>
) {}

用法示例:

import { createReducer } from '@acemarke/redux-starter-kit'

function addTodo(state, action) {
  const { newTodo } = action.payload

  // Can safely call state.push() here
  state.push({ ...newTodo, completed: false })
}

function toggleTodo(state, action) {
  const { index } = action.payload

  const todo = state[index]
  // Can directly modify the todo object
  todo.completed = !todo.completed
}

const todosReducer = createReducer([], {
  ADD_TODO: addTodo,
  TOGGLE_TODO: toggleTodo
})

这并不意味着您必须在您的 case reducers 中编写代码来改变现有的 state 值,您仍然可以编写不可变地更新状态的代码。 您可以将 immer 视为一个安全网,如果代码是以直接改变状态的方式编写的,immer 将确保这种更新不可变地发生。 另一方面,以下代码仍然有效:

import { createReducer } from '@acemarke/redux-starter-kit'

function addTodo(state, action) {
  const { newTodo } = action.payload

  // Updates the state immutably without relying on immer
  return [...state, { ...newTodo, completed: false }]
}

function toggleTodo(state, action) {
  const { index } = action.payload

  const todo = state[index]
  // Updates the todo object immutably withot relying on immer
  return state.map((todo, i) => {
    if (i !== index) return todo
    return { ...todo, completed: !todo.completed }
  })
}

const todosReducer = createReducer([], {
  ADD_TODO: addTodo,
  TOGGLE_TODO: toggleTodo
})

createSelector

selector 库中的 createSelector 实用程序,重新导出以便于使用。 它充当来自 Reselect 的标准 createSelector 函数的超集。 主要改进是能够使用字符串键路径定义“输入选择器”,或返回基于键路径对象的对象结果。 它还接受针对更具体用例的自定义选项对象。

有关详细信息,请参阅selector 使用文档

function createSelector(
    // Can either be:
    //    - An array containing selector functions, string keypaths, and argument objects
    //    - An object whose keys are selector functions and string keypaths
    paths : Array<Function | string | Object> | Object<string, string | Function>
)

用法示例:

// Define input selector using a string keypath
const getSubtotal = createSelector(['shop.items'], items => {
  // return value here
})

// Define input selectors as a mix of other selectors and string keypaths
const getTax = createSelector(
  [getSubtotal, 'shop.taxPercent'],
  (subtotal, taxPercent) => {
    // return value here
  }
)

// Define input selector using a custom argument index to access a prop
const getTabContent = createSelector(
  [{ path: 'tabIndex', argIndex: 1 }],
  tabIndex => {
    // return value here
  }
)

const getContents = createSelector({ foo: 'foo', bar: 'nested.bar' })
// Returns an object like:  {foo, bar}

createNextState

immer 中的默认不可变更新函数,在此处重新导出为 < code>createNextState(通常也称为produce

combineReducers

Redux 的combineReducers,为了方便重新导出。 虽然 configureStore 在内部调用它,但您可能希望自己调用它来组合多级切片缩减器。

compose

Redux 的 compose。 它从右到左组合函数。 这是一个函数式编程实用程序。 您可能希望使用它来连续应用多个商店自定义增强器/功能。

redux-starter-kit

npm versionnpm downloads

A simple set of tools to make using Redux easier

npm install @acemarke/redux-starter-kit

Purpose

The redux-starter-kit package is intended to help address three common complaints about Redux:

  • "Configuring a Redux store is too complicated"
  • "I have to add a lot of packages to get Redux to do anything useful"
  • "Redux requires too much boilerplate code"

We can't solve every use case, but in the spirit of create-react-app and apollo-boost, we can try to provide some tools that abstract over the setup process and handle the most common use cases, as well as include some useful utilities that will let the user simplify their application code.

This package is not intended to solve every possible complaint about Redux, and is deliberately limited in scope. It does not address concepts like "reusable encapsulated Redux modules", data fetching, folder or file structures, managing entity relationships in the store, and so on.

What's Included

redux-starter-kit includes:

  • A configureStore() function with simplified configuration options. It can automatically combine your slice reducers, adds whatever Redux middleware you supply, includes redux-thunk by default, and enables use of the Redux DevTools Extension.
  • A createReducer() utility that lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses the immer library to let you write simpler immutable updates with normal mutative code, like state.todos[3].completed = true.
  • An improved version of the widely used createSelector utility for creating memoized selector functions, which can accept string keypaths as "input selectors" (re-exported from the selectorator library).

API Reference

configureStore

A friendlier abstraction over the standard Redux createStore function. Takes a single configuration object parameter, with the following options:

function configureStore({
    // A single reducer function that will be used as the root reducer,
    // or an object of slice reducers that will be passed to combineReducers()
    reducer: Object<string, Function> | Function,
    // An array of Redux middlewares.  If not supplied, defaults to just redux-thunk.
    middleware: Array<MiddlewareFunction>,
    // Built-in support for devtools. Defaults to true.
    devTools: boolean,
    // Same as current createStore.
    preloadedState : State,
    // Same as current createStore.
    enhancer : ReduxStoreEnhancer,
})

Basic usage:

import { configureStore } from '@acemarke/redux-starter-kit'

import rootReducer from './reducers'

const store = configureStore({ reducer: rootReducer })
// The store now has redux-thunk added and the Redux DevTools Extension is turned on

Full example:

import {
  configureStore,
  getDefaultMiddleware
} from '@acemarke/redux-starter-kit'

// We'll use redux-logger just as an example of adding another middleware
import logger from 'redux-logger'

// And use redux-batch as an example of adding enhancers
import { reduxBatch } from '@manaflair/redux-batch'

import todosReducer from './todos/todosReducer'
import visibilityReducer from './visibility/visibilityReducer'

const reducer = {
  todos: todosReducer,
  visibility: visibilityReducer
}

const middleware = [...getDefaultMiddleware(), logger]

const preloadedState = {
  todos: [
    {
      text: 'Eat food',
      completed: true
    },
    {
      text: 'Exercise',
      completed: false
    }
  ],
  visibilityFilter: 'SHOW_COMPLETED'
}

const store = configureStore({
  reducer,
  middleware,
  devTools: NODE_ENV !== 'production',
  preloadedState,
  enhancers: [reduxBatch]
})

// The store has been created with these options:
// - The slice reducers were automatically passed to combineReducers()
// - redux-thunk and redux-logger were added as middleware
// - The Redux DevTools Extension is disabled for production
// - The middleware, batch, and devtools enhancers were automatically composed together

getDefaultMiddleware

getDefaultMiddleware is useful if you need to add custom middlewares without removing redux-starter-kit's default middleware. Currently it returns an array with redux-thunk.

createReducer

A utility function to create reducers that handle specific action types, similar to the example function in the "Reducing Boilerplate" Redux docs page. Takes an initial state value and an object that maps action types to case reducer functions. Internally, it uses the immer library, so you can write code in your case reducers that mutates the existing state value, and it will correctly generate immutably-updated state values instead.

function createReducer(
  initialState: State,
  actionsMap: Object<String, Function>
) {}

Example usage:

import { createReducer } from '@acemarke/redux-starter-kit'

function addTodo(state, action) {
  const { newTodo } = action.payload

  // Can safely call state.push() here
  state.push({ ...newTodo, completed: false })
}

function toggleTodo(state, action) {
  const { index } = action.payload

  const todo = state[index]
  // Can directly modify the todo object
  todo.completed = !todo.completed
}

const todosReducer = createReducer([], {
  ADD_TODO: addTodo,
  TOGGLE_TODO: toggleTodo
})

This doesn't mean that you have to write code in your case reducers that mutates the existing state value, you can still write code that updates the state immutably. You can think of immer as a safety net, if the code is written in a way that mutates the state directly, immer will make sure that such update happens immutably. On the other hand the following code is still valid:

import { createReducer } from '@acemarke/redux-starter-kit'

function addTodo(state, action) {
  const { newTodo } = action.payload

  // Updates the state immutably without relying on immer
  return [...state, { ...newTodo, completed: false }]
}

function toggleTodo(state, action) {
  const { index } = action.payload

  const todo = state[index]
  // Updates the todo object immutably withot relying on immer
  return state.map((todo, i) => {
    if (i !== index) return todo
    return { ...todo, completed: !todo.completed }
  })
}

const todosReducer = createReducer([], {
  ADD_TODO: addTodo,
  TOGGLE_TODO: toggleTodo
})

createSelector

The createSelector utility from the selectorator library, re-exported for ease of use. It acts as a superset of the standard createSelector function from Reselect. The primary improvements are the ability to define "input selectors" using string keypaths, or return an object result based on an object of keypaths. It also accepts an object of customization options for more specific use cases.

For more specifics, see the selectorator usage documentation.

function createSelector(
    // Can either be:
    //    - An array containing selector functions, string keypaths, and argument objects
    //    - An object whose keys are selector functions and string keypaths
    paths : Array<Function | string | Object> | Object<string, string | Function>
)

Example usage:

// Define input selector using a string keypath
const getSubtotal = createSelector(['shop.items'], items => {
  // return value here
})

// Define input selectors as a mix of other selectors and string keypaths
const getTax = createSelector(
  [getSubtotal, 'shop.taxPercent'],
  (subtotal, taxPercent) => {
    // return value here
  }
)

// Define input selector using a custom argument index to access a prop
const getTabContent = createSelector(
  [{ path: 'tabIndex', argIndex: 1 }],
  tabIndex => {
    // return value here
  }
)

const getContents = createSelector({ foo: 'foo', bar: 'nested.bar' })
// Returns an object like:  {foo, bar}

createNextState

The default immutable update function from the immer library, re-exported here as createNextState (also commonly referred to as produce)

combineReducers

Redux's combineReducers, re-exported for convenience. While configureStore calls this internally, you may wish to call it yourself to compose multiple levels of slice reducers.

compose

Redux's compose. It composes functions from right to left. This is a functional programming utility. You might want to use it to apply several store custom enhancers/ functions in a row.

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