├── .gitignore
├── .prettierrc.json
├── CNAME
├── README.md
├── docs
├── FAQ.md
├── api
│ ├── Store.md
│ ├── api-reference.md
│ ├── applyMiddleware.md
│ ├── bindActionCreators.md
│ ├── combineReducers.md
│ ├── compose.md
│ └── createStore.md
├── components
│ └── DetailedExplanation.jsx
├── faq
│ ├── Actions.md
│ ├── CodeStructure.md
│ ├── DesignDecisions.md
│ ├── General.md
│ ├── ImmutableData.md
│ ├── Miscellaneous.md
│ ├── OrganizingState.md
│ ├── Performance.md
│ ├── ReactRedux.md
│ ├── Reducers.md
│ └── StoreSetup.md
├── introduction
│ ├── CoreConcepts.md
│ ├── Ecosystem.md
│ ├── Examples.md
│ ├── GettingStarted.md
│ ├── Installation.md
│ ├── LearningResources.md
│ └── why-rtk-is-redux-today.md
├── redux-toolkit
│ └── overview.md
├── style-guide
│ └── style-guide.md
├── tutorials
│ ├── essentials
│ │ ├── part-1-overview-concepts.md
│ │ ├── part-2-app-structure.md
│ │ ├── part-3-data-flow.md
│ │ ├── part-4-using-data.md
│ │ ├── part-5-async-logic.md
│ │ ├── part-6-performance-normalization.md
│ │ ├── part-7-rtk-query-basics.md
│ │ └── part-8-rtk-query-advanced.md
│ ├── fundamentals
│ │ ├── part-1-overview.md
│ │ ├── part-2-concepts-data-flow.md
│ │ ├── part-3-state-actions-reducers.md
│ │ ├── part-4-store.md
│ │ ├── part-5-ui-and-react.md
│ │ ├── part-6-async-logic.md
│ │ ├── part-7-standard-patterns.md
│ │ └── part-8-modern-redux.md
│ ├── quick-start.md
│ ├── tutorials-index.md
│ ├── typescript.md
│ └── videos.md
├── understanding
│ ├── history-and-design
│ │ ├── PriorArt.md
│ │ └── middleware.md
│ └── thinking-in-redux
│ │ ├── Glossary.md
│ │ ├── Motivation.md
│ │ └── ThreePrinciples.md
└── usage
│ ├── CodeSplitting.md
│ ├── ConfiguringYourStore.md
│ ├── ImplementingUndoHistory.md
│ ├── IsolatingSubapps.md
│ ├── MigratingToRedux.md
│ ├── ReducingBoilerplate.md
│ ├── ServerRendering.md
│ ├── Troubleshooting.md
│ ├── UsageWithTypescript.md
│ ├── UsingObjectSpreadOperator.md
│ ├── WritingTests.mdx
│ ├── deriving-data-selectors.md
│ ├── index.md
│ ├── structuring-reducers
│ ├── BasicReducerStructure.md
│ ├── BeyondCombineReducers.md
│ ├── ImmutableUpdatePatterns.md
│ ├── InitializingState.md
│ ├── NormalizingStateShape.md
│ ├── PrerequisiteConcepts.md
│ ├── RefactoringReducersExample.md
│ ├── ReusingReducerLogic.md
│ ├── SplittingReducerLogic.md
│ ├── StructuringReducers.md
│ ├── UpdatingNormalizedData.md
│ └── UsingCombineReducers.md
│ └── writing-logic-thunks.mdx
├── errors.json
├── package.json
└── website
├── .gitignore
├── README.md
├── _redirects
├── docusaurus.config.js
├── package.json
├── sidebars.js
├── src
├── css
│ └── custom.css
├── js
│ └── monokaiTheme.js
└── pages
│ ├── errors.js
│ ├── index.js
│ └── styles.module.css
├── static
├── CNAME
└── img
│ ├── cogs-solid.svg
│ ├── cubes-solid.svg
│ ├── external-link-square-alt-solid.svg
│ ├── favicon
│ └── favicon.ico
│ ├── github-brands.svg
│ ├── noun_Check_1870817.svg
│ ├── noun_debugging_1978252.svg
│ ├── redux-logo-landscape.png
│ ├── redux.svg
│ ├── redux_white.svg
│ └── tutorials
│ ├── essentials
│ ├── ReduxAsyncDataFlowDiagram.gif
│ ├── ReduxDataFlowDiagram.gif
│ ├── api-slice-contents.png
│ ├── devtools-action-stacktrace.png
│ ├── devtools-cached-invalidation-refetching.png
│ ├── devtools-cached-requests.png
│ ├── devtools-done-clicking.png
│ ├── devtools-first-action.png
│ ├── devtools-initial.png
│ ├── devtools-posts-fulfilled.png
│ ├── devtools-posts-pending.png
│ ├── devtools-rtkq-cache.png
│ ├── disabled-posts-fetching.png
│ ├── example-initial-posts-list.png
│ ├── example-initial-posts.png
│ ├── example-postAdded-action.png
│ ├── notifications-initial.png
│ ├── notifications-new.png
│ ├── one-way-data-flow.png
│ ├── posts-unknownAuthor.png
│ ├── postslist-optimized.png
│ ├── postslist-rerender.png
│ ├── userpage-rerender.png
│ └── working_post_list.png
│ └── fundamentals
│ ├── devtools-action-tab.png
│ ├── devtools-async-todoAdded-action.png
│ ├── devtools-async-todoAdded-diff.png
│ ├── devtools-diff-tab.png
│ ├── devtools-state-tab.png
│ ├── devtools-todosLoaded-action.png
│ ├── immutable-error.png
│ ├── initial-state-updates.png
│ ├── meaningOfLife-enhancer-logging.png
│ ├── print-middleware-logging.png
│ ├── sayhi-enhancer-logging.png
│ ├── todos-app-headerLoading.png
│ ├── todos-app-markedCompleted.png
│ ├── todos-app-screenshot.png
│ ├── todos-app-selectorFilters.png
│ ├── todos-app-showCompleted.png
│ └── todos-app-todosLoaded.png
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | docs-back
3 |
4 | coverage
5 |
6 | dist
7 | lib
8 | es
9 | types
10 |
11 | website/translated_docs
12 | website/build/
13 | website/node_modules
14 | website/i18n/*
15 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "tabWidth": 2,
5 | "trailingComma": "none",
6 | "arrowParens": "avoid"
7 | }
8 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | cn.redux.js.org
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [Redux 中文文档](http://github.com/camsong/redux-in-chinese) [](https://gitter.im/camsong/redux-in-chinese?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://travis-ci.org/camsong/redux-in-chinese)
2 |
3 |
4 |
5 | ➡️在线文档地址:https://cn.redux.js.org/
6 |
7 | Redux 是 JavaScript 状态容器,提供可预测化的状态管理。
8 | (如果你需要一个 WordPress 框架,请查看 [Redux Framework](https://reduxframework.com/)。)
9 |
10 | 可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。不仅于此,它还提供
11 | 超爽的开发体验,比如有一个[时间旅行调试器可以编辑后实时预览](https://github.com/reduxjs/redux-devtools)。
12 |
13 | Redux 除了和 [React](https://facebook.github.io/react/) 一起用外,还支持其它界面库。
14 | 它体小精悍(只有 2kB,包括依赖)。
15 |
16 | ## 安装
17 | Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法。 它围绕着 Redux core,包含我们认为构建 Redux 应用程序必不可少的包和函数。Redux Toolkit 基于我们建议的最佳实践来开发,简化了大多数 Redux 任务,防止了常见错误,并使编写 Redux 应用程序变得更加容易。
18 |
19 | ```
20 | npm install @reduxjs/toolkit react-redux
21 | ```
22 |
23 | 只安装 Redux core
24 |
25 | ```
26 | npm install redux
27 | ```
28 |
29 | 更多信息,访问 [安装文档](https://cn.redux.js.org/introduction/installation/)
30 |
31 | ## 文档
32 |
33 | - [入门](https://cn.redux.js.org/introduction/getting-started)
34 | - [教程](https://cn.redux.js.org/tutorials/index)
35 | - [使用引导](https://cn.redux.js.org/usage/)
36 | - [常见问题](https://cn.redux.js.org/faq)
37 | - [API 文档](https://cn.redux.js.org/api/api-reference)
38 |
39 |
40 | ## 借鉴
41 |
42 | Redux 改进了 [Flux](https://facebook.github.io/flux/) 的思想,但通过从 [Elm](https://github.com/evancz/elm-architecture-tutorial/) 中汲取灵感来避免其复杂性。即使您没有使用过 Flux 或 Elm,Redux 也只需几分钟即可上手。
43 |
44 | ## Logo
45 |
46 | 官方 Logo [在 Github 上可以找到](https://github.com/reduxjs/redux/tree/master/logo)。
47 |
48 | ## 重要里程碑
49 |
50 | ### 4.x 里程碑:
51 |
52 | 2022.10.1 全面完成 4.x 官方文档的翻译和校验,特别感谢以下贡献者的辛勤付出:
53 |
54 | * [HuiFei](https://github.com/guanwanxiao)
55 | * [Gonson International](https://github.com/GonsonInter)
56 | * [雨季sky](https://github.com/yujidxl)
57 | * [Flora](https://github.com/Flora-wyy)
58 | * [hellocathi](https://github.com/hellocathi)
59 | * [Healer](https://github.com/zxb-hub)
60 | * [izeal77](https://github.com/izeal77)
61 |
62 | ## 贡献者
63 |
64 | 在线链接:https://github.com/nefe/redux-in-chinese/graphs/contributors
65 |
66 | 所有贡献者列表
67 |
68 |
69 | **本文档翻译流程符合 [ETC 翻译规范](https://github.com/react-guide/ETC),欢迎你来一起完善**
70 |
71 | ## License
72 |
73 | MIT
--------------------------------------------------------------------------------
/docs/FAQ.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: faq
3 | title: FAQ 目录
4 | description: 'FAQ 目录: Redux 常见问答'
5 | ---
6 |
7 | # Redux 常见问答
8 |
9 | ## 目录
10 |
11 | - **常见问题**
12 | - [什么时候需要学习 Redux?](faq/General.md#when-should-i-learn-redux)
13 | - [什么时候需要使用 Redux?](faq/General.md#when-should-i-use-redux)
14 | - [Redux 只能与 React 一起使用吗?](faq/General.md#can-redux-only-be-used-with-react)
15 | - [是否需要特定的构建工具才能使用 Redux?](faq/General.md#do-i-need-to-have-a-particular-build-tool-to-use-redux)
16 | - **Reducers**
17 | - [如何在两个 reducers 之间共享 state?必须使用 combineReducers 吗?](faq/Reducers.md#how-do-i-share-state-between-two-reducers-do-i-have-to-use-combinereducers)
18 | - [是否必须使用 switch 语句来处理 actions 吗?](faq/Reducers.md#do-i-have-to-use-the-switch-statement-to-handle-actions)
19 | - **组织 State**
20 | - [必须将所有的 state 都放入 Redux 吗?应该使用 React 的 setState() 吗?](faq/OrganizingState.md#do-i-have-to-put-all-my-state-into-redux-should-i-ever-use-reacts-setstate)
21 | - [可以将函数、promises 或其他不可序列化的项放入 store state 吗?](faq/OrganizingState.md#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)
22 | - [如何组织 state 中的嵌套或重复数据?](faq/OrganizingState.md#how-do-i-organize-nested-or-duplicate-data-in-my-state)
23 | - [应该将表单 state 或其他 UI state 放入 store 吗?](faq/OrganizingState.md#should-i-put-form-state-or-other-ui-state-in-my-store)
24 | - **Store 设置**
25 | - [可以或者应该创建多个 stores 吗?可以直接导入 stores,并在组件中使用它吗?](faq/StoreSetup.md#can-or-should-i-create-multiple-stores-can-i-import-my-store-directly-and-use-it-in-components-myself)
26 | - [Store enhancer 中可以有多个 middleware 链吗?Middleware 函数中的 next 和 dispatch 有什么区别?](faq/StoreSetup.md#is-it-ok-to-have-more-than-one-middleware-chain-in-my-store-enhancer-what-is-the-difference-between-next-and-dispatch-in-a-middleware-function)
27 | - [如何能够只订阅 state 的一部分?可以将 dispatch action 作为订阅的一部分吗?](faq/StoreSetup.md#how-do-i-subscribe-to-only-a-portion-of-the-state-can-i-get-the-dispatched-action-as-part-of-the-subscription)
28 | - **Actions**
29 | - [为什么 type 应该是一个字符串,或者至少是可序列化的?为什么 action types 应该是常量?](faq/Actions.md#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)
30 | - [Reducers 和 actions 之间总是存在一对一的映射关系吗?](faq/Actions.md#is-there-always-a-one-to-one-mapping-between-reducers-and-actions)
31 | - [如何表示 AJAX 调用等“副作用”?为什么我们需要 action creator、thunk 和 middleware 这些来处理异步行为?](faq/Actions.md#how-can-i-represent-side-effects-such-as-ajax-calls-why-do-we-need-things-like-action-creators-thunks-and-middleware-to-do-async-behavior)
32 | - [应该使用哪个异步 middleware?如何在 thunk、sagas、observables 或其他中做出选择?](faq/Actions.md#what-async-middleware-should-i-use-how-do-you-decide-between-thunks-sagas-observables-or-something-else)
33 | - [应该从一个 action creator 连续 dispatch 多个 actions 吗?](faq/Actions.md#should-i-dispatch-multiple-actions-in-a-row-from-one-action-creator)
34 | - **不可变数据**
35 | - [不可变数据有什么好处?](faq/ImmutableData.md#what-are-the-benefits-of-immutability)
36 | - [为什么 Redux 需要不可变数据?](faq/ImmutableData.md#why-is-immutability-required-by-redux)
37 | - [有哪些方法可以实现数据不可变?必须使用 Immer 吗?](faq/ImmutableData.md#what-approaches-are-there-for-handling-data-immutability-do-i-have-to-use-immer)
38 | - [使用 JavaScript 进行不可变操作会有什么问题?](faq/ImmutableData.md#what-are-the-issues-with-using-plain-javascript-for-immutable-operations)
39 | - **代码结构**
40 | - [文件结构应该是什么样的?应该如何对 action creators 和 reducers 进行分组?Selectors 应该放在哪里?](faq/CodeStructure.md#what-should-my-file-structure-look-like-how-should-i-group-my-action-creators-and-reducers-in-my-project-where-should-my-selectors-go)
41 | - [应该如何在 reducers 和 action creators 之间划分逻辑?“业务逻辑”应该放在哪里?](faq/CodeStructure.md#how-should-i-split-my-logic-between-reducers-and-action-creators-where-should-my-business-logic-go)
42 | - [为什么应该使用 action creators?](faq/CodeStructure.md#why-should-i-use-action-creators)
43 | - [Websockets 以及其他持久连接应该放在哪里?](faq/CodeStructure.md#where-should-websockets-and-other-persistent-connections-live)
44 | - [如何在非组件文件中使用 Redux store?](faq/CodeStructure.md#how-can-i-use-the-redux-store-in-non-component-files)
45 | - **性能**
46 | - [Redux 在性能和架构方面的“扩展性”如何?](faq/Performance.md#how-well-does-redux-scale-in-terms-of-performance-and-architecture)
47 | - [为每个 action 调用“所有的 reducers”会不会很慢?](faq/Performance.md#wont-calling-all-my-reducers-for-each-action-be-slow)
48 | - [必须在 reducer 中深拷贝 state 吗?拷贝 state 不会很慢吗?](faq/Performance.md#do-i-have-to-deep-clone-my-state-in-a-reducer-isnt-copying-my-state-going-to-be-slow)
49 | - [如何减少 store 更新事件的数量?](faq/Performance.md#how-can-i-reduce-the-number-of-store-update-events)
50 | - [“单状态树”会导致内存问题吗?Dispatch 很多 actions 会占用内存吗?](faq/Performance.md#will-having-one-state-tree-cause-memory-problems-will-dispatching-many-actions-take-up-memory)
51 | - [缓存远端数据会导致内存问题吗?](faq/Performance.md#will-caching-remote-data-cause-memory-problems)
52 | - **设计决策**
53 | - [为什么 Redux 不将 state 和 action 传递给订阅者?](faq/DesignDecisions.md#why-doesnt-redux-pass-the-state-and-action-to-subscribers)
54 | - [为什么 Redux 不支持使用类 class 做 action 和 reducer ?](faq/DesignDecisions.md#why-doesnt-redux-support-using-classes-for-actions-and-reducers)
55 | - [为什么 middleware 签名使用柯里化?](faq/DesignDecisions.md#why-does-the-middleware-signature-use-currying)
56 | - [为什么 applyMiddleware 使用闭包进行 dispatch?](faq/DesignDecisions.md#why-does-applymiddleware-use-a-closure-for-dispatch)
57 | - [为什么 `combineReducers` 在调用每个 reducer 时不接收整个 state 作为第三个参数?](faq/DesignDecisions.md#why-doesnt-combinereducers-include-a-third-argument-with-the-entire-state-when-it-calls-each-reducer)
58 | - [为什么 mapDispatchToProps 不允许使用来自 `getState()` 或 `mapStateToProps()` 的返回值?](faq/DesignDecisions.md#why-doesnt-mapdispatchtoprops-allow-use-of-return-values-from-getstate-or-mapstatetoprops)
59 | - **React Redux**
60 | - [为什么应该使用 React-Redux?](faq/ReactRedux.md#why-should-i-use-react-redux)
61 | - [为什么我的组件没有重新渲染,或者 mapStateToProps 没有运行?](faq/ReactRedux.md#why-isnt-my-component-re-rendering-or-my-mapstatetoprops-running)
62 | - [为什么我的组件经常重新渲染?](faq/ReactRedux.md#why-is-my-component-re-rendering-too-often)
63 | - [如何加速 mapStateToProps?](faq/ReactRedux.md#how-can-i-speed-up-my-mapstatetoprops)
64 | - [为什么 connect 过的组件中没有 this.props.dispatch 可用?](faq/ReactRedux.md#why-dont-i-have-this-props-dispatch-available-in-my-connected-component)
65 | - [应该只 connect 顶层组件,还是可以 connect 树中的多个组件?](faq/ReactRedux.md#should-i-only-connect-my-top-component-or-can-i-connect-multiple-components-in-my-tree)
66 | - **其他**
67 | - [有没有更大的、“真正生产环境的” Redux 项目?](faq/Miscellaneous.md#are-there-any-larger-real-redux-projects)
68 | - [如何在 Redux 中实现身份验证?](faq/Miscellaneous.md#how-can-i-implement-authentication-in-redux)
69 |
--------------------------------------------------------------------------------
/docs/api/Store.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: store
3 | title: Store
4 | description: 'API > Store: the core Redux store methods'
5 | ---
6 |
7 | # Store
8 |
9 | Store 就是用来维持应用所有的 [state 树](../understanding/thinking-in-redux/Glossary.md#state) 的一个对象。
10 | 改变 store 内 state 的惟一途径是对它 dispatch 一个 [action](../understanding/thinking-in-redux/Glossary.md#action)。
11 |
12 | Store 不是类。它只是有几个方法的对象。
13 | 要创建它,只需要把根部的 [reducing 函数](../understanding/thinking-in-redux/Glossary.md#reducer) 传递给 [`createStore`](createStore.md)。
14 |
15 | > ##### Flux 用户使用注意
16 | >
17 | > 如果你以前使用 Flux,那么你只需要注意一个重要的区别。Redux 没有 Dispatcher 且不支持多个 store。**相反,只有一个单一的 store 和一个根级的 reduce 函数[reducing function](../understanding/thinking-in-redux/Glossary.md#reducer)**。随着应用不断变大,你应该把根级的 reducer 拆成多个小的 reducers,分别独立地操作 state 树的不同部分,而不是添加新的 stores。然后你可以使用 [`combineReducers`](combineReducers.md) 来连接他们。这就像一个 React 应用只有一个根级的组件,这个根组件又由很多小组件构成。
18 |
19 | ### Store 方法
20 |
21 | - [`getState()`](#getstate)
22 | - [`dispatch(action)`](#dispatchaction)
23 | - [`subscribe(listener)`](#subscribelistener)
24 | - [`replaceReducer(nextReducer)`](#replacereducernextreducer)
25 |
26 | ## Store 方法
27 |
28 | ### getState()
29 |
30 | 返回应用当前的 state 树。
31 | 它与 store 的最后一个 reducer 返回值相同。
32 |
33 | #### 返回值
34 |
35 | _(any)_: 应用当前的 state 树。
36 |
37 | ---
38 |
39 |
40 |
41 | ### dispatch(action)
42 |
43 | dispatch action。这是触发 state 变化的惟一途径。
44 |
45 | ****
46 | 将使用当前 [`getState()`](#getstate) 的结果和传入的 `action` 以同步方式的调用 store 的 reducer 函数。它的返回值会被作为下一个 state。从现在开始,这就成为了 [`getState()`](#getstate) 的返回值,同时变化监听器(change listener)会被触发。
47 |
48 | > ##### Flux 用户使用注意
49 | >
50 | > 当你在 [reducer](../understanding/thinking-in-redux/Glossary.md#reducer) 内部调用 `dispatch` 时,将会抛出错误提示“Reducers may not dispatch actions.(Reducer 内不能 dispatch action)”。这就相当于 Flux 里的 “Cannot dispatch in a middle of dispatch(dispatch 过程中不能再 dispatch)”,但并不会引起对应的错误。在 Flux 里,当 Store 处理 action 和触发 update 事件时,dispatch 是禁止的。这个限制并不好,因为他限制了不能在生命周期回调里 dispatch action,还有其它一些本来很正常的地方。
51 | >
52 | > 在 Redux 里,只会在根 reducer 返回新 state 结束后再会调用事件监听器,因此,你可以在事件监听器里再做 dispatch。惟一使你不能在 reducer 中途 dispatch 的原因是要确保 reducer 没有副作用。如果 action 处理会产生副作用,正确的做法是使用异步 [action 创建函数](../understanding/thinking-in-redux/Glossary.md#action-creator)。
53 |
54 | #### 参数
55 |
56 | 1. `action` (_Object_†): 描述应用变化的普通对象。Action 是把数据传入 store 的惟一途径,所以任何数据,无论来自 UI 事件,网络回调或者是其它资源如 WebSockets,最终都应该以 action 的形式被 dispatch。按照约定,action 具有 `type` 字段来表示它的类型。type 也可被定义为常量或者是从其它模块引入。最好使用字符串,而不是 [Symbols](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Symbol) 作为 action,因为字符串是可以被序列化的。除了 `type` 字段外,action 对象的结构完全取决于你。参照 [Flux 标准 Action](https://github.com/acdlite/flux-standard-action) 获取如何组织 action 的建议。
57 |
58 | #### Returns
59 |
60 | (Object†): 要 dispatch 的 action。
61 |
62 | #### Notes
63 |
64 | † 使用 [`createStore`](createStore.md) 创建的 “纯正” store 只支持普通对象类型的 action,而且会立即传到 reducer 来执行。
65 |
66 | 但是,如果你用 [`applyMiddleware`](applyMiddleware.md) 来套住 [`createStore`](createStore.md) 时,middleware 可以修改 action 的执行,并支持执行 dispatch [异步 actions](../understanding/thinking-in-redux/Glossary.md#async-action)。异步 action 通常使用异步原语如 Promise、Observable 或者 Thunk。
67 |
68 | Middleware 是由社区创建,并不会同 Redux 一起发行。你需要手动安装 [redux-thunk](https://github.com/gaearon/redux-thunk) 或者 [redux-promise](https://github.com/acdlite/redux-promise) 库。你也可以创建自己的 middleware。
69 |
70 | 想学习如何描述异步 API 调用?看一下 action 创建函数里当前的 state,执行一个有副作用的操作,或者以链式操作执行它们,参照 [`applyMiddleware`](applyMiddleware.md) 中的示例。
71 |
72 | #### Example
73 |
74 | ```js
75 | import { createStore } from 'redux'
76 | const store = createStore(todos, ['Use Redux'])
77 |
78 | function addTodo(text) {
79 | return {
80 | type: 'ADD_TODO',
81 | text
82 | }
83 | }
84 |
85 | store.dispatch(addTodo('Read the docs'))
86 | store.dispatch(addTodo('Read about the middleware'))
87 | ```
88 |
89 | ---
90 |
91 | ### subscribe(listener)
92 |
93 | 添加一个变化监听器。每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。你可以在回调函数里调用 [`getState()`](#getstate) 来拿到当前 state。
94 |
95 | 你可以在变化监听器里面进行 [`dispatch()`](#dispatchaction),但你需要注意下面的事项:
96 |
97 | 1. 监听器调用 [`dispatch()`](#dispatchaction) 仅仅应当发生在响应用户的 actions 或者特殊的条件限制下(比如: 在 store 有一个特殊的字段时 dispatch action)。虽然没有任何条件去调用 [`dispatch()`](#dispatchaction) 在技术上是可行的,但是随着每次 [`dispatch()`](#dispatchaction) 改变 store 可能会导致陷入无穷的循环。
98 |
99 | 2. 订阅器(subscriptions) 在每次 [`dispatch()`](#dispatchaction) 调用之前都会保存一份快照。当你在正在调用监听器(listener)的时候订阅(subscribe)或者去掉订阅(unsubscribe),对当前的 [`dispatch()`](#dispatchaction) 不会有任何影响。但是对于下一次的 [`dispatch()`](#dispatchaction),无论嵌套与否,都会使用订阅列表里最近的一次快照。
100 |
101 | 3. 订阅器不应该注意到所有 state 的变化,在订阅器被调用之前,往往由于嵌套的 [`dispatch()`](#dispatchaction) 导致 state 发生多次的改变。保证所有的监听器都注册在 [`dispatch()`](#dispatchaction) 启动之前,这样,在调用监听器的时候就会传入监听器所存在时间里最新的一次 state。
102 |
103 | 这是一个底层 API。多数情况下,你不会直接使用它,会使用一些 React(或其它库)的绑定。如果你想让回调函数执行的时候使用当前的 state,你可以 [写一个定制的 `observeStore` 工具](https://github.com/rackt/redux/issues/303#issuecomment-125184409)。 `Store` 也是一个 [`Observable`](https://github.com/zenparsing/es-observable), 所以你可以使用 [RxJS](https://github.com/ReactiveX/RxJS) 的这样的库来 `subscribe` 订阅更新。
104 |
105 | 如果需要解绑这个变化监听器,执行 `subscribe` 返回的函数即可。
106 |
107 | #### 参数
108 |
109 | 1. `listener` (_Function_): 每当 dispatch action 的时候都会执行的回调。state 树中的一部分可能已经变化。你可以在回调函数里调用 [`getState()`](#getstate) 来拿到当前 state。store 的 reducer 应该是纯函数,因此你可能需要对 state 树中的引用做深度比较来确定它的值是否有变化。
110 |
111 | ##### 返回值
112 |
113 | (_Function_): 一个可以解绑变化监听器的函数。
114 |
115 | ##### 示例
116 |
117 | ```js
118 | function select(state) {
119 | return state.some.deep.property
120 | }
121 |
122 | let currentValue
123 | function handleChange() {
124 | let previousValue = currentValue
125 | currentValue = select(store.getState())
126 |
127 | if (previousValue !== currentValue) {
128 | console.log(
129 | 'Some deep nested property changed from',
130 | previousValue,
131 | 'to',
132 | currentValue
133 | )
134 | }
135 | }
136 |
137 | const unsubscribe = store.subscribe(handleChange)
138 | unsubscribe()
139 | ```
140 |
141 | ---
142 |
143 | ### replaceReducer(nextReducer)
144 |
145 | 替换 store 当前用来计算 state 的 reducer。
146 |
147 | 这是一个高级 API。只有在你需要实现代码分隔,而且需要立即加载一些 reducer 的时候才可能会用到它。在实现 Redux 热加载机制的时候也可能会用到。
148 |
149 | #### 参数
150 |
151 | 1. `nextReducer` (_Function_) store 会使用的下一个 reducer。
152 |
--------------------------------------------------------------------------------
/docs/api/api-reference.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: api-reference
3 | title: API 参考
4 | hide_title: false
5 | ---
6 |
7 | # API 参考
8 |
9 | Redux 的 API 非常少。Redux 为你定义了一系列的约定(例如 [reducers](../understanding/thinking-in-redux/Glossary.md#reducer)),同时提供了少量的辅助函数来把这些约定整合到一起。
10 |
11 | 这一章会介绍所有的 Redux API。记住,Redux 只关心如何管理 state。在实际的项目中,你还需要使用如 [react-redux](https://github.com/gaearon/react-redux)这样的 UI 绑定库。
12 |
13 | ### 顶级暴露的方法
14 |
15 | - [createStore(reducer, [preloadedState], [enhancer])](createStore.md)
16 | - [combineReducers(reducers)](combineReducers.md)
17 | - [applyMiddleware(...middlewares)](applyMiddleware.md)
18 | - [bindActionCreators(actionCreators, dispatch)](bindActionCreators.md)
19 | - [compose(...functions)](compose.md)
20 |
21 | ### Store API
22 |
23 | - [Store](Store.md)
24 | - [getState()](Store.md#getState)
25 | - [dispatch(action)](Store.md#dispatchaction)
26 | - [subscribe(listener)](Store.md#subscribelistener)
27 | - [replaceReducer(nextReducer)](Store.md#replacereducernextreducer)
28 |
29 | ### 引入
30 |
31 | 上面介绍的所有函数都是顶级暴露的方法。都可以这样引入:
32 |
33 | #### ES6
34 |
35 | ```js
36 | import { createStore } from 'redux'
37 | ```
38 |
39 | #### ES5 (CommonJS)
40 |
41 | ```js
42 | var createStore = require('redux').createStore
43 | ```
44 |
45 | #### ES5 (UMD build)
46 |
47 | ```js
48 | var createStore = Redux.createStore
49 | ```
50 |
--------------------------------------------------------------------------------
/docs/api/applyMiddleware.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: applymiddleware
3 | title: applyMiddleware
4 | hide_title: true
5 | description: 'API > applyMiddleware: extending the Redux store'
6 | ---
7 |
8 |
9 |
10 | # `applyMiddleware(...middleware)`
11 |
12 | 使用包含自定义功能的 middleware 来扩展 Redux 是一种推荐的方式。Middleware 可以让你包装 store 的 [`dispatch`](Store.md#dispatchaction) 方法来达到你想要的目的。同时, middleware 还拥有“可组合”这一关键特性。多个 middleware 可以被组合到一起使用,形成 middleware 链。其中,每个 middleware 都不需要关心链中它前后的 middleware 的任何信息。
13 |
14 | Middleware 最常见的使用场景是无需引用大量代码或依赖类似 [Rx](https://github.com/Reactive-Extensions/RxJS) 的第三方库实现异步 actions。这种方式可以让你像 dispatch 一般的 actions 那样 dispatch [异步 actions](../understanding/thinking-in-redux/Glossary.md#async-action)。
15 |
16 | 例如,[redux-thunk](https://github.com/gaearon/redux-thunk) 支持 dispatch function,以此让 action creator 控制反转。被 dispatch 的 function 会接收 [`dispatch`](Store.md#dispatchaction) 作为参数,并且可以异步调用它。这类的 function 就称为 _thunk_。另一个 middleware 的示例是 [redux-promise](https://github.com/acdlite/redux-promise)。它支持 dispatch 一个异步的 [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) action,并且在 Promise resolve 后可以 dispatch 一个普通的 action。
17 |
18 | Middleware 并不需要和 [`createStore`](createStore.md) 绑在一起使用,也不是 Redux 架构的基础组成部分,但它带来的益处让我们认为有必要在 Redux 核心中包含对它的支持。因此,虽然不同的 middleware 可能在易用性和用法上有所不同,它仍被作为扩展 [`dispatch`](Store.md#dispatchaction) 的唯一标准的方式。
19 |
20 | #### 参数
21 |
22 | - `...middleware` (_arguments_): 遵循 Redux _middleware API_ 的函数。每个 middleware 接受 [`Store`](Store.md) 的 [`dispatch`](Store.md#dispatchaction) 和 [`getState`](Store.md#getState) 函数作为命名参数,并返回一个函数。该函数会被传入被称为 `next` 的下一个 middleware 的 dispatch 方法,并返回一个接收 action 的新函数,这个函数可以直接调用 `next(action)`,或者在其他需要的时刻调用,甚至根本不去调用它。调用链中最后一个 middleware 会接受真实的 store 的 [`dispatch`](Store.md#dispatchaction) 方法作为 `next` 参数,并借此结束调用链。所以,middleware 的函数签名是 `({ getState, dispatch }) => next => action`。
23 |
24 | #### 返回值
25 |
26 | (_Function_) 一个应用了 middleware 后的 store enhancer。这个 store enhancer 的签名是 `createStore => createStore`,但是最简单的使用方法就是直接作为最后一个 `enhancer` 参数传递给 [`createStore()`](createStore.md) 函数。
27 |
28 | #### 示例: 自定义 Logger Middleware
29 |
30 | ```js
31 | import { createStore, applyMiddleware } from 'redux'
32 | import todos from './reducers'
33 |
34 | function logger({ getState }) {
35 | return next => action => {
36 | console.log('will dispatch', action)
37 |
38 | // 调用 middleware 链中下一个 middleware 的 dispatch。
39 | const returnValue = next(action)
40 |
41 | console.log('state after dispatch', getState())
42 |
43 | // 一般会是 action 本身,除非
44 | // 后面的 middleware 修改了它。
45 | return returnValue
46 | }
47 | }
48 |
49 | const store = createStore(todos, ['Use Redux'], applyMiddleware(logger))
50 |
51 | store.dispatch({
52 | type: 'ADD_TODO',
53 | text: 'Understand the middleware'
54 | })
55 | // (middleware 将打印如下信息:)
56 | // will dispatch: { type: 'ADD_TODO', text: 'Understand the middleware' }
57 | // state after dispatch: [ 'Use Redux', 'Understand the middleware' ]
58 | ```
59 |
60 | #### 示例: 使用 Thunk Middleware 来做异步 Action
61 |
62 | ```js
63 | import { createStore, combineReducers, applyMiddleware } from 'redux'
64 | import thunk from 'redux-thunk'
65 | import * as reducers from './reducers'
66 |
67 | const reducer = combineReducers(reducers)
68 | // applyMiddleware 为 createStore 注入了 middleware:
69 | const store = createStore(reducer, applyMiddleware(thunk))
70 |
71 | function fetchSecretSauce() {
72 | return fetch('https://www.google.com/search?q=secret+sauce')
73 | }
74 |
75 | // 这些是你已熟悉的普通 action creator。
76 | // 它们返回的 action 不需要任何 middleware 就能被 dispatch。
77 | // 但是,他们只表达「事实」,并不表达「异步数据流」
78 | function makeASandwich(forPerson, secretSauce) {
79 | return {
80 | type: 'MAKE_SANDWICH',
81 | forPerson,
82 | secretSauce
83 | }
84 | }
85 |
86 | function apologize(fromPerson, toPerson, error) {
87 | return {
88 | type: 'APOLOGIZE',
89 | fromPerson,
90 | toPerson,
91 | error
92 | }
93 | }
94 |
95 | function withdrawMoney(amount) {
96 | return {
97 | type: 'WITHDRAW',
98 | amount
99 | }
100 | }
101 |
102 | // 即使不使用 middleware,你也可以 dispatch action:
103 | store.dispatch(withdrawMoney(100))
104 |
105 | // 但是怎样处理异步 action 呢,
106 | // 比如 API 调用,或者是路由跳转?
107 |
108 | // 来看一下 thunk。
109 | // Thunk 就是一个返回函数的函数。
110 | // 下面就是一个 thunk。
111 | function makeASandwichWithSecretSauce(forPerson) {
112 | // 控制反转!
113 | // 返回一个接收 `dispatch` 的函数。
114 | // Thunk middleware 知道如何把异步的 thunk action 转为普通 action。
115 | return function(dispatch) {
116 | return fetchSecretSauce().then(
117 | sauce => dispatch(makeASandwich(forPerson, sauce)),
118 | error => dispatch(apologize('The Sandwich Shop', forPerson, error))
119 | )
120 | }
121 | }
122 |
123 | // Thunk middleware 可以让我们像 dispatch 普通 action
124 | // 一样 dispatch 异步的 thunk action。
125 | store.dispatch(makeASandwichWithSecretSauce('Me'))
126 |
127 | // 它甚至负责回传 thunk 被 dispatch 后返回的值,
128 | // 所以可以继续串连 Promise,调用它的 .then() 方法。
129 | store.dispatch(makeASandwichWithSecretSauce('My wife')).then(() => {
130 | console.log('Done!')
131 | })
132 |
133 | // 实际上,可以写一个 dispatch 其它 action creator 里
134 | // 普通 action 和异步 action 的 action creator,
135 | // 而且可以使用 Promise 来控制数据流。
136 | function makeSandwichesForEverybody() {
137 | return function(dispatch, getState) {
138 | if (!getState().sandwiches.isShopOpen) {
139 | // 返回 Promise 并不是必须的,但这是一个很好的约定,
140 | // 为了让调用者能够在异步的 dispatch 结果上直接调用 .then() 方法。
141 | return Promise.resolve()
142 | }
143 |
144 | // 可以 dispatch 普通 action 对象和其它 thunk,
145 | // 这样我们就可以在一个数据流中组合多个异步 action。
146 | return dispatch(makeASandwichWithSecretSauce('My Grandma'))
147 | .then(() =>
148 | Promise.all([
149 | dispatch(makeASandwichWithSecretSauce('Me')),
150 | dispatch(makeASandwichWithSecretSauce('My wife'))
151 | ])
152 | )
153 | .then(() => dispatch(makeASandwichWithSecretSauce('Our kids')))
154 | .then(() =>
155 | dispatch(
156 | getState().myMoney > 42
157 | ? withdrawMoney(42)
158 | : apologize('Me', 'The Sandwich Shop')
159 | )
160 | )
161 | }
162 | }
163 |
164 | // 这在服务端渲染时很有用,因为我可以等到数据
165 | // 准备好后,同步的渲染应用。
166 |
167 | import { renderToString } from 'react-dom/server'
168 |
169 | store
170 | .dispatch(makeSandwichesForEverybody())
171 | .then(() => response.send(renderToString(
{this.props.sandwiches.join('mustard')}
192 | } 193 | } 194 | 195 | export default connect(state => ({ 196 | sandwiches: state.sandwiches 197 | }))(SandwichShop) 198 | ``` 199 | 200 | #### 小贴士 201 | 202 | - Middleware 只是包装了 store 的 [`dispatch`](Store.md#dispatchaction) 方法。技术上讲,任何 middleware 能做的事情,都可能通过手动包装 `dispatch` 调用来实现,但是放在同一个地方统一管理会使整个项目的扩展变的容易得多。 203 | 204 | - 如果除了 `applyMiddleware`,你还用了其它 store enhancer,一定要把 `applyMiddleware` 放到组合链的前面,因为 middleware 可能会包含异步操作。比如,它应该在 [redux-devtools](https://github.com/reduxjs/redux-devtools) 前面,否则 DevTools 就看不到 Promise middleware 里 dispatch 的 action 了。 205 | 206 | - 如果你想有条件地使用 middleware,记住只 import 需要的部分: 207 | 208 | ```js 209 | const middleware = [a, b] 210 | if (process.env.NODE_ENV !== 'production') { 211 | const c = require('some-debug-middleware') 212 | const d = require('another-debug-middleware') 213 | middleware = [...middleware, c, d] 214 | } 215 | 216 | const store = createStore( 217 | reducer, 218 | preloadedState, 219 | applyMiddleware(...middleware) 220 | ) 221 | ``` 222 | 223 | 这样做有利于打包时去掉不需要的模块,减小打包文件的大小。 224 | 225 | - 有想过 `applyMiddleware` 本质是什么吗?它肯定是比 middleware 还强大的扩展机制。实际上,`applyMiddleware` 只是被称为 Redux 最强大的扩展机制的 [store enhancer](../understanding/thinking-in-redux/Glossary.md#store-enhancer) 中的一个范例而已。你不太可能需要实现自己的 store enhancer。另一个 store enhancer 示例是 [redux-devtools](https://github.com/reduxjs/redux-devtools)。Middleware 并没有 store enhancer 强大,但是开发起来却更容易。 226 | 227 | - Middleware 听起来比实际要复杂一些。真正理解 middleware 的唯一办法是了解现有的 middleware 是如何工作的,并尝试自己实现。需要的功能可能错综复杂,但是你会发现大部分 middleware 实际上很小,只有 10 行左右,是通过对它们的嵌套和组合使用来达到最终的目的。 228 | 229 | - 想要使用多个 store enhancer,可以使用 [`compose()`](./compose.md) 方法。 230 | -------------------------------------------------------------------------------- /docs/api/bindActionCreators.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: bindactioncreators 3 | title: bindActionCreators 4 | hide_title: true 5 | description: 'API > bindActionCreators: wrapping action creators for dispatching' 6 | --- 7 | 8 | 9 | 10 | # `bindActionCreators(actionCreators, dispatch)` 11 | 12 | 把一个 value 为不同 [action creator](../understanding/thinking-in-redux/Glossary.md#action-creator) 的对象,转成拥有同名 key 的对象。同时使用 [`dispatch`](Store.md#dispatchaction) 对每个 action creator 进行包装,以便可以直接调用它们。 13 | 14 | 一般情况下你可以直接在 [`Store`](Store.md) 实例上调用 [`dispatch`](Store.md#dispatchaction)。如果你在 React 中使用 Redux,[react-redux](https://github.com/gaearon/react-redux) 会提供 [`dispatch`](Store.md#dispatchaction) 函数让你直接调用它 。 15 | 16 | 惟一会使用到 `bindActionCreators` 的场景是当你需要把 action creator 往下传到一个组件上,却不想让这个组件觉察到 Redux 的存在,而且不希望把 [`dispatch`](Store.md#dispatchaction) 或 Redux store 传给它。 17 | 18 | 为方便起见,你也可以传入 action creator 作为第一个参数,并且得到一个 dispatch 函数作为返回值。 19 | 20 | #### 参数 21 | 22 | 1. `actionCreators` (_Function_ or _Object_): 一个 [action creator](../understanding/thinking-in-redux/Glossary.md#action-creator),或者一个 value 是 action creator 的对象。 23 | 24 | 2. `dispatch` (_Function_): 一个由 [`Store`](Store.md) 实例提供的 [`dispatch`](Store.md#dispatchaction) 函数。 25 | 26 | #### 返回值 27 | 28 | (_Function_ or _Object_): 一个与原对象类似的对象,只不过这个对象的 value 都是会直接 dispatch 原 action creator 返回的结果的函数。如果传入一个单独的函数作为 `actionCreators`,那么返回的结果也是一个单独的函数。 29 | 30 | #### 示例 31 | 32 | #### `TodoActionCreators.js` 33 | 34 | ```js 35 | export function addTodo(text) { 36 | return { 37 | type: 'ADD_TODO', 38 | text 39 | } 40 | } 41 | 42 | export function removeTodo(id) { 43 | return { 44 | type: 'REMOVE_TODO', 45 | id 46 | } 47 | } 48 | ``` 49 | 50 | #### `SomeComponent.js` 51 | 52 | ```js 53 | import { Component } from 'react' 54 | import { bindActionCreators } from 'redux' 55 | import { connect } from 'react-redux' 56 | 57 | import * as TodoActionCreators from './TodoActionCreators' 58 | console.log(TodoActionCreators) 59 | // { 60 | // addTodo: Function, 61 | // removeTodo: Function 62 | // } 63 | 64 | function TodoListContainer(props) { 65 | // react-redux 注入: 66 | const { dispatch, todos } = props 67 | 68 | // 这是一个很好的 bindActionCreators 用例: 69 | // 你希望子组件完全不知道 Redux. 70 | // 我们现在创建这些函数的绑定版本,以便我们可以 71 | // 之后将它们传给子组件. 72 | 73 | const boundActionCreators = useMemo( 74 | () => bindActionCreators(TodoActionCreators, dispatch), 75 | [dispatch] 76 | ) 77 | console.log(boundActionCreators) 78 | // { 79 | // addTodo: Function, 80 | // removeTodo: Function 81 | // } 82 | 83 | useEffect(() => { 84 | // 注意: 这不起作用: 85 | // TodoActionCreators.addTodo('Use Redux') 86 | 87 | // 你只是在调用一个创建 action 的函数。 88 | // 你也必须同时 dispatch 一个 action! 89 | 90 | // 这将起到作用: 91 | let action = TodoActionCreators.addTodo('Use Redux') 92 | dispatch(action) 93 | }, []) 94 | 95 | return