• h0_825296
  • 123KB
  • zip
  • 0
  • VIP专享
  • 0
  • 2022-06-16 01:10
还原作用 一个自以为是的库,用于为创建动作和减少器。 主要目标是将动作本身用作化简器中的引用,而不是字符串常量。 安装 # NPM npm install redux-act --save # Yarn yarn add redux-act 您还可以使用或NPM CDN的(主要用于在线演示/摘录)。 浏览器支持:此库使用String.prototype.startsWith ,IE11不支持。 如果您要定位此浏览器,请确保添加一个polyfill。 。 内容 用法 即使有一个名为createAction的函数,它实际上也会根据Redux词汇表创建一个action creator 。 将函数
# redux-act An opinionated lib to create actions and reducers for [Redux]( The main goal is to use actions themselves as references inside the reducers rather than string constants. ## Install ```bash # NPM npm install redux-act --save # Yarn yarn add redux-act ``` You can also use a [browser friendly compiled file]( or the [minified version]( from NPM CDN (mostly for online demo / snippets). **Browser support**: this lib uses `String.prototype.startsWith` which is not supported by IE11. Be sure to add a polyfill if you are targeting this browser. [Learn more]( ## Content - [Usage](#usage) - [FAQ](#faq) - [Advanced usage](#advanced-usage) - [API](#api) - [createAction](#createactiondescription-payloadreducer-metareducer) - [action creator](#action-creator) - [createReducer](#createreducerhandlers-defaultstate) - [reducer](#reducer) - [assignAll](#assignallactioncreators-stores) - [bindAll](#bindallactioncreators-stores) - [batch](#batchactions) - [disbatch](#disbatchstore--dispatch-actions) - [asError](#aserroraction) - [types](#types) - [Cookbook](#cookbook) - [Compatibility](#compatibility) - [Adding and removing actions](#adding-and-removing-actions) - [Async actions](#async-actions) - [Enable or disable batch](#enable-or-disable-batch) - [TypeScript](#typescript) - [Loggers](#loggers) - [Redux Logger](#redux-logger) ## Usage Even if there is a function named `createAction`, it actually creates an `action creator` according to Redux glossary. It was just a bit overkill to name the function `createActionCreator`. If you are not sure if something is an action or an action creator, just remember that actions are plain objects while action creators are functions. ```javascript // Import functions import { createStore } from 'redux'; import { createAction, createReducer } from 'redux-act'; // Create an action creator (description is optional) const add = createAction('add some stuff'); const increment = createAction('increment the state'); const decrement = createAction('decrement the state'); // Create a reducer // (ES6 syntax, see Advanced usage below for an alternative for ES5) const counterReducer = createReducer({ [increment]: (state) => state + 1, [decrement]: (state) => state - 1, [add]: (state, payload) => state + payload, }, 0); // <-- This is the default state // Create the store const counterStore = createStore(counterReducer); // Dispatch actions counterStore.dispatch(increment()); // counterStore.getState() === 1 counterStore.dispatch(increment()); // counterStore.getState() === 2 counterStore.dispatch(decrement()); // counterStore.getState() === 1 counterStore.dispatch(add(5)); // counterStore.getState() === 6 ``` ## FAQ - **Does it work with Redux devtools?** Yes. - **Do reducers work with combineReducers?** Of course, they are just normal reducers after all. Remember that according to the `combineReducers` checks, you will need to provide a default state when creating each reducer before combining them. - **How does it work?** There is not much magic. A generated id is prepended to each action type and will be used inside reducers instead of the string constants used inside Redux by default. - **Can you show how different it is from writing classic Redux?** Sure, you can check both commits to update [counter example]( and [todomvc example]( You can also run both examples with `npm install && npm start` inside each folder. - **Why having two syntax to create reducers?** The one with only a map of `action => reduce function` doesn't allow much. This is why the other one is here, in case you would need a small state inside the reducer, having something similar as an actor, or whatever you feel like. Also, one of the syntax is ES6 only. - **Inside a reducer, why is it `(state, payload) => newState` rather than `(state, action) => newState`?** You can find more info about that on the `createReducer` API below, but basically, that's because an action is composed of metadata handled by the lib and your payload. Since you only care about that part, better to have it directly. You can switch back to the full action if necessary of course. - **Why have you done that? Aren't string constants good enough?** I know that the Redux doc states that such magic isn't really good, that saving a few lines of code isn't worth hiding such logic. I can understand that. And don't get me wrong, the main goal of this lib isn't to reduce boilerplate (even if I like that it does) but to use the actions themselves as keys for the reducers rather than strings which are error prone. You never know what the new dev on your project might do... Maybe (s)he will not realize that the new constant (s)he just introduced was already existing and now everything is broken and a wormhole will appear and it will be the end of mankind. Let's prevent that! ## Advanced usage ```javascript import { createStore } from 'redux'; import { createAction, createReducer } from 'redux-act'; // You can create several action creators at once // (but that's probably not the best way to do it) const [increment, decrement] = ['inc', 'dec'].map(createAction); // When creating action creators, the description is optional // it will only be used for devtools and logging stuff. // It's better to put something but feel free to leave it empty if you want to. const replace = createAction(); // By default, the payload of the action is the first argument // when you call the action. If you need to support several arguments, // you can specify a function on how to merge all arguments into // an unique payload. let append = createAction('optional description', (...args) => args.join('')); // There is another pattern to create reducers // and it works fine with ES5! (maybe even ES3 \o/) const stringReducer = createReducer(function (on) { on(replace, (state, payload) => payload); on(append, (state, payload) => state += payload); // Warning! If you use the same action twice, // the second one will override the previous one. }, 'missing a lette'); // <-- Default state // Rather than binding the action creators each time you want to use them, // you can do it once and for all as soon as you have the targeted store // assignTo: mutates the action creator itself // bindTo: returns a new action creator assigned to the store const stringStore = createStore(stringReducer); replace.assignTo(stringStore); append = append.bindTo(stringStore); // Now, when calling actions, they will be automatically dispatched append('r'); // stringStore.getState() === 'missing a letter' replace('a'); // stringStore.getState() === 'a' append('b', 'c', 'd'); // stringStore.getState() === 'abcd' // If you really need serializable actions, using string constant rather // than runtime generated id, just use a uppercase description (with eventually some underscores) // and it will be use as the id of the action const doSomething = createAction('STRING_CONSTANT'); doSomething(1); // { type: 'STRING_CONSTANT', payload: 1} // Little bonus, if you need to support metadata around your action, // like needed data but not really part of the payload, you add a second function const metaAction = createAction('desc', arg => arg, arg => 'so meta!'); // Metadata will be the third argument of the reduce function createReducer({ [metaAction]: (state, payload, meta) => payload }); ``` ## API ### createAction([description], [payloadReducer], [metaReducer]) **Parameters** - **description** (string, optional): used by logging and devtools when displaying the action. If this parameter is uppercase only, with underscore