pax_global_header 0000666 0000000 0000000 00000000064 14365314725 0014524 g ustar 00root root 0000000 0000000 52 comment=f4b3ab9ac5370c5520d08383c5fc88e1e1c64587
redux-4.2.1/ 0000775 0000000 0000000 00000000000 14365314725 0012657 5 ustar 00root root 0000000 0000000 redux-4.2.1/.babelrc.js 0000664 0000000 0000000 00000001003 14365314725 0014657 0 ustar 00root root 0000000 0000000 const { NODE_ENV } = process.env
module.exports = {
presets: [
[
'@babel/env',
{
targets: {
browsers: ['ie >= 11']
},
exclude: ['transform-async-to-generator', 'transform-regenerator'],
modules: false,
loose: true
}
]
],
plugins: [
// don't use `loose` mode here - need to copy symbols when spreading
'@babel/proposal-object-rest-spread',
NODE_ENV === 'test' && '@babel/transform-modules-commonjs'
].filter(Boolean)
}
redux-4.2.1/.codesandbox/ 0000775 0000000 0000000 00000000000 14365314725 0015226 5 ustar 00root root 0000000 0000000 redux-4.2.1/.codesandbox/ci.json 0000664 0000000 0000000 00000000111 14365314725 0016505 0 ustar 00root root 0000000 0000000 {
"sandboxes": [
"vanilla",
"vanilla-ts"
],
"node": "14"
}
redux-4.2.1/.editorconfig 0000664 0000000 0000000 00000000460 14365314725 0015334 0 ustar 00root root 0000000 0000000 # EditorConfig helps developers define and maintain
# consistent coding styles between different editors and IDEs.
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false
redux-4.2.1/.eslintignore 0000664 0000000 0000000 00000000122 14365314725 0015355 0 ustar 00root root 0000000 0000000 **/dist/**
**/node_modules/**
**/server.js
**/webpack.config*.js
**/flow-typed/**
redux-4.2.1/.eslintrc.js 0000664 0000000 0000000 00000000407 14365314725 0015117 0 ustar 00root root 0000000 0000000 module.exports = {
extends: 'react-app',
settings: {
react: {
version: '16.8'
}
},
rules: {
'jsx-a11y/href-no-hash': 'off'
},
overrides: [
{
files: 'test/**/*.js',
env: {
jest: true,
},
},
],
}
redux-4.2.1/.gitbook.yaml 0000664 0000000 0000000 00000000071 14365314725 0015255 0 ustar 00root root 0000000 0000000 structure:
readme: README.md
summary: docs/README.md
redux-4.2.1/.github/ 0000775 0000000 0000000 00000000000 14365314725 0014217 5 ustar 00root root 0000000 0000000 redux-4.2.1/.github/FUNDING.yml 0000664 0000000 0000000 00000000020 14365314725 0016024 0 ustar 00root root 0000000 0000000 github: timdorr
redux-4.2.1/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 14365314725 0016402 5 ustar 00root root 0000000 0000000 redux-4.2.1/.github/ISSUE_TEMPLATE/Bug_report.md 0000664 0000000 0000000 00000002577 14365314725 0021047 0 ustar 00root root 0000000 0000000 ---
name: "\U0001F41BBug report"
about: Something is wrong with Redux.
---
### Prior Issues
Are there any existing issues or PRs that relate to this problem? If so, link them here.
### What is the current behavior?
What does Redux do right now.
### Steps to Reproduce
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://codesandbox.io or similar.
### What is the expected behavior?
What should Redux be doing?
### Environment Details
Which versions of Redux, and which browser and OS are affected by this issue? Did this work in previous versions of Redux?
redux-4.2.1/.github/ISSUE_TEMPLATE/Feature_request.md 0000664 0000000 0000000 00000002346 14365314725 0022074 0 ustar 00root root 0000000 0000000 ---
name: 👍 Feature Request
about: I'd like Redux to do something new.
---
## New Features
### What is the new or updated feature that you are suggesting?
### Why should this feature be included?
### What docs changes are needed to explain this?
redux-4.2.1/.github/ISSUE_TEMPLATE/config.yml 0000664 0000000 0000000 00000000421 14365314725 0020367 0 ustar 00root root 0000000 0000000 blank_issues_enabled: false
contact_links:
- name: 🤔 Questions and Help
url: https://redux.js.org/introduction/getting-started#help-and-discussion
about: This is a bug tracker, not a support system. For usage questions, please use our support resources.
redux-4.2.1/.github/ISSUE_TEMPLATE/documentation-edit.md 0000664 0000000 0000000 00000000350 14365314725 0022516 0 ustar 00root root 0000000 0000000 ---
name: "\U0001F4DD Documentation Fix"
about: Fixing a problem in an existing docs page
---
## What docs page needs to be fixed?
- **Section**:
- **Page**:
## What is the problem?
## What should be changed to fix the problem?
redux-4.2.1/.github/ISSUE_TEMPLATE/documentation-new.md 0000664 0000000 0000000 00000001326 14365314725 0022366 0 ustar 00root root 0000000 0000000 ---
name: "\U0001F4D6 New/Updated Documentation Content"
about: Adding a new docs page, or updating content in an existing docs page
---
## What docs page is being added or updated?
- **Section**:
- **Page**:
## For Adding New Content
### What kind of content category is this page (tutorial, how-to, explanation, reference)?
### Who is the intended target audience?
#### What knowledge are we assuming they have?
### What are the intended results or takeaways from reading this page?
### What is the most critical info they should learn?
## For Updating Existing Content
### What updates should be made to the page?
### Do these updates change any of the assumptions or target audience? If so, how do they change?
redux-4.2.1/.github/PULL_REQUEST_TEMPLATE.md 0000664 0000000 0000000 00000000544 14365314725 0020023 0 ustar 00root root 0000000 0000000 Thanks for the PR!
To better assist you, please select the type of PR you want to create.
Click the "Preview" tab above, and click on the link for the PR type:
- [:bug: Bug fix or new feature](?template=bugfix.md)
- [:memo: Documentation Fix](?template=documentation-edit.md)
- [:book: New/Updated Documentation Content](?template=documentation-new.md)
redux-4.2.1/.github/PULL_REQUEST_TEMPLATE/ 0000775 0000000 0000000 00000000000 14365314725 0017476 5 ustar 00root root 0000000 0000000 redux-4.2.1/.github/PULL_REQUEST_TEMPLATE/bugfix.md 0000664 0000000 0000000 00000001555 14365314725 0021312 0 ustar 00root root 0000000 0000000 ---
name: :bug: Bug fix or new feature
about: Fixing a problem with Redux
---
## PR Type
### Does this PR add a new _feature_, or fix a _bug_?
### Why should this PR be included?
## Checklist
- [ ] Have you added an explanation of what your changes do and why you'd like us to include them?
- [ ] Is there an existing issue for this PR?
- _link issue here_
- [ ] Have the files been linted and formatted?
- [ ] Have the docs been updated to match the changes in the PR?
- [ ] Have the tests been updated to match the changes in the PR?
- [ ] Have you run the tests locally to confirm they pass?
## New Features
### What new capabilities does this PR add?
### What docs changes are needed to explain this?
## Bug Fixes
### What is the current behavior, and the steps to reproduce the issue?
### What is the expected behavior?
### How does this PR fix the problem?
redux-4.2.1/.github/PULL_REQUEST_TEMPLATE/documentation-edit.md 0000664 0000000 0000000 00000000555 14365314725 0023621 0 ustar 00root root 0000000 0000000 ---
name: :memo: Documentation Fix
about: Fixing a problem in an existing docs page
---
## Checklist
- [ ] Is there an existing issue for this PR?
- _link issue here_
- [ ] Have the files been linted and formatted?
## What docs page needs to be fixed?
- **Section**:
- **Page**:
## What is the problem?
## What changes does this PR make to fix the problem?
redux-4.2.1/.github/PULL_REQUEST_TEMPLATE/documentation-new.md 0000664 0000000 0000000 00000001641 14365314725 0023462 0 ustar 00root root 0000000 0000000 ---
name: :book: New/Updated Documentation Content
about: Adding a new docs page, or updating content in an existing docs page
---
## PR Type
**Does this PR add a _new_ page, or update an _existing_ page?**
## Checklist
- [ ] Is there an existing issue for this PR?
- _link issue here_
- [ ] Have the files been linted and formatted?
## What docs page is being added or updated?
- **Section**:
- **Page**:
## For Adding New Content
### What kind of content category is this page (tutorial, how-to, explanation, reference)?
### Who is the intended target audience?
#### What knowledge are we assuming they have?
### What are the intended results or takeaways from reading this page?
### What is the most critical info they should learn?
## For Updating Existing Content
### What updates should be made to the page?
### Do these updates change any of the assumptions or target audience? If so, how do they change?
redux-4.2.1/.github/workflows/ 0000775 0000000 0000000 00000000000 14365314725 0016254 5 ustar 00root root 0000000 0000000 redux-4.2.1/.github/workflows/size.yaml 0000664 0000000 0000000 00000000556 14365314725 0020120 0 ustar 00root root 0000000 0000000 name: Bundle Size
on: [pull_request]
jobs:
build:
name: Check compressed size
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2-beta
with:
fetch-depth: 1
- uses: preactjs/compressed-size-action@v2
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
pattern: './{dist,es,lib}/*.{js,mjs}'
redux-4.2.1/.github/workflows/test.yaml 0000664 0000000 0000000 00000001463 14365314725 0020123 0 ustar 00root root 0000000 0000000 name: Tests
on:
push:
branches: [4.x]
pull_request:
branches: [4.x]
jobs:
build:
name: Test Suite
runs-on: ubuntu-latest
steps:
- name: Set up Node
uses: actions/setup-node@v1
with:
node-version: 14.x
- name: Checkout code
uses: actions/checkout@v2
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.OS }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.OS }}-npm-
${{ runner.OS }}-
- name: Install dependencies
run: npm ci
- name: Check formatting
run: npm run format:check
- name: Lint code
run: npm run lint
- name: Run test suite
run: npm test
redux-4.2.1/.gitignore 0000664 0000000 0000000 00000000231 14365314725 0014643 0 ustar 00root root 0000000 0000000 .DS_Store
*.log
node_modules
dist
lib
es
coverage
types
website/translated_docs
website/build/
website/node_modules
website/.docusaurus/
website/i18n/*
redux-4.2.1/.prettierrc.json 0000664 0000000 0000000 00000000074 14365314725 0016014 0 ustar 00root root 0000000 0000000 {
"semi": false,
"singleQuote": true,
"tabWidth": 2
}
redux-4.2.1/CHANGELOG.md 0000664 0000000 0000000 00000000341 14365314725 0014466 0 ustar 00root root 0000000 0000000 # Change Log
This project adheres to [Semantic Versioning](http://semver.org/).
Every release, along with the migration instructions, is documented on the Github [Releases](https://github.com/reduxjs/redux/releases) page.
redux-4.2.1/CNAME 0000664 0000000 0000000 00000000015 14365314725 0013421 0 ustar 00root root 0000000 0000000 redux.js.org
redux-4.2.1/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000006234 14365314725 0015463 0 ustar 00root root 0000000 0000000 # Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at dan.abramov@me.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
redux-4.2.1/CONTRIBUTING.md 0000664 0000000 0000000 00000012060 14365314725 0015107 0 ustar 00root root 0000000 0000000 # Contributing
We are open to, and grateful for, any contributions made by the community. By contributing to Redux, you agree to abide by the [code of conduct](https://github.com/reduxjs/redux/blob/master/CODE_OF_CONDUCT.md).
## Reporting Issues and Asking Questions
Before opening an issue, please search the [issue tracker](https://github.com/reduxjs/redux/issues) to make sure your issue hasn't already been reported.
### Bugs and Improvements
We use the issue tracker to keep track of bugs and improvements to Redux itself, its examples, and the documentation. We encourage you to open issues to discuss improvements, architecture, theory, internal implementation, etc. If a topic has been discussed before, we will ask you to join the previous discussion.
As Redux is stable software, changes to its behavior are very carefully considered. Any pull requests that involve breaking changes should be made against the `next` branch.
### Getting Help
**For support or usage questions like “how do I do X with Redux” and “my code doesn't work”, please search and ask on [StackOverflow with a Redux tag](http://stackoverflow.com/questions/tagged/redux?sort=votes&pageSize=50) first.**
We ask you to do this because StackOverflow has a much better job at keeping popular questions visible. Unfortunately good answers get lost and outdated on GitHub.
Some questions take a long time to get an answer. **If your question gets closed or you don't get a reply on StackOverflow for longer than a few days,** we encourage you to post an issue linking to your question. We will close your issue but this will give people watching the repo an opportunity to see your question and reply to it on StackOverflow if they know the answer.
Please be considerate when doing this as this is not the primary purpose of the issue tracker.
### Help Us Help You
On both websites, it is a good idea to structure your code and question in a way that is easy to read to entice people to answer it. For example, we encourage you to use syntax highlighting, indentation, and split text in paragraphs.
Please keep in mind that people spend their free time trying to help you. You can make it easier for them if you provide versions of the relevant libraries and a runnable small project reproducing your issue. You can put your code on [JSBin](http://jsbin.com) or, for bigger projects, on GitHub. Make sure all the necessary dependencies are declared in `package.json` so anyone can run `npm install && npm start` and reproduce your issue.
## Development
Visit the [issue tracker](https://github.com/reduxjs/redux/issues) to find a list of open issues that need attention.
Fork, then clone the repo:
```sh
git clone https://github.com/your-username/redux.git
```
### Building
#### Building Redux
Running the `build` task will create a CommonJS module-per-module build, a ES Modules build and a UMD build.
```sh
npm run build
```
### Testing and Linting
To only run linting:
```sh
npm run lint
```
To only run tests:
```sh
npm run test
```
To continuously watch and run tests, run the following:
```sh
npm run test:watch
```
### Docs
Improvements to the documentation are always welcome. You can find them in the [`docs`](/docs) path. We use [Docusaurus](https://docusaurus.io/) to build our documentation website. The website is published automatically whenever the `master` branch is updated.
### Examples
Redux comes with [official examples](http://redux.js.org/docs/introduction/Examples.html) to demonstrate various concepts and best practices.
When adding a new example, please adhere to the style and format of the existing examples, and try to reuse as much code as possible. For example, `index.html`, `server.js`, and `webpack.config.js` can typically be reused.
#### Testing the Examples
To test the official Redux examples, run the following:
```sh
npm run examples:test
```
Not all examples have tests. If you see an example project without tests, you are very welcome to add them in a way consistent with the examples that have tests.
Please visit the [Examples page](http://redux.js.org/docs/introduction/Examples.html) for information on running individual examples.
### Sending a Pull Request
For non-trivial changes, please open an issue with a proposal for a new feature or refactoring before starting on the work. We don't want you to waste your efforts on a pull request that we won't want to accept.
On the other hand, sometimes the best way to start a conversation _is_ to send a pull request. Use your best judgement!
In general, the contribution workflow looks like this:
- Open a new issue in the [Issue tracker](https://github.com/reduxjs/redux/issues).
- Fork the repo.
- Create a new feature branch based off the `master` branch.
- Make sure all tests pass and there are no linting errors.
- Submit a pull request, referencing any issues it addresses.
Please try to keep your pull request focused in scope and avoid including unrelated commits.
After you have submitted your pull request, we'll try to get back to you as soon as possible. We may suggest some changes or improvements.
Thank you for contributing!
redux-4.2.1/LICENSE-logo.md 0000664 0000000 0000000 00000015537 14365314725 0015234 0 ustar 00root root 0000000 0000000 The [Redux logo](./logo/) is dedicated to the public domain and licensed under [CC0](<[CC0](http://creativecommons.org/publicdomain/zero/1.0/)>).
You can copy, modify, and distribute it, even for commercial purposes, all without asking permission.
[Read more about CC0.](http://creativecommons.org/publicdomain/zero/1.0/)
You can find its legal text below.
#### Creative Commons Zero v1.0 Universal
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
{lastUpdated && (
Last updated at {new Date(lastUpdated).toLocaleTimeString()}.{' '}
)}
{!isFetching && (
)}
Redux is a predictable state container for JavaScript apps.
(Not to be confused with a WordPress framework – [Redux Framework](https://reduxframework.com/).)
It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as [live code editing combined with a time traveling debugger](https://github.com/reduxjs/redux-devtools).
You can use Redux together with [React](https://reactjs.org), or with any other view library.
It is tiny (2kB, including dependencies).
> **Note**: We are currently planning a rewrite of the Redux docs. Please take some time to **[fill out this survey on what content is most important in a docs site](https://docs.google.com/forms/d/e/1FAIpQLSfzIkY3fXZ8PrQKScYMK0YoEgALfAK2qQ0mOj1_ibKv2qDTuQ/viewform)**. Thanks!
[](https://travis-ci.org/reduxjs/redux)
[](https://www.npmjs.com/package/redux)
[](https://www.npmjs.com/package/redux)
[](https://discord.gg/0ZcbPKXt5bZ6au5t)
[](https://changelog.com/187)
## Learn Redux
We have a variety of resources available to help you learn Redux, no matter what your background or learning style is.
### Just the Basics
If you're brand new to Redux and want to understand the basic concepts, see:
- The **[Motivation](https://redux.js.org/introduction/motivation)** behind building Redux, the **[Core Concepts](https://redux.js.org/introduction/coreconcepts)**, and the **[Three Principles](https://redux.js.org/introduction/threeprinciples)**.
- The **[basic tutorial in the Redux docs](https://redux.js.org/basics)**
- Redux creator Dan Abramov's **free ["Getting Started with Redux" video series](https://egghead.io/series/getting-started-with-redux)** on Egghead.io
- Redux co-maintainer Mark Erikson's **["Redux Fundamentals" slideshow](http://blog.isquaredsoftware.com/2018/03/presentation-reactathon-redux-fundamentals/)** and **[list of suggested resources for learning Redux](http://blog.isquaredsoftware.com/2017/12/blogged-answers-learn-redux/)**
- If you learn best by looking at code and playing with it, check out our list of **[Redux example applications](https://redux.js.org/introduction/examples)**, available as separate projects in the Redux repo, and also as interactive online examples on CodeSandbox.
- The **[Redux Tutorials](https://github.com/markerikson/react-redux-links/blob/master/redux-tutorials.md)** section of the **[React/Redux links list](https://github.com/markerikson/react-redux-links)**. Here's a top list of our recommended tutorials:
- Dave Ceddia's posts [What Does Redux Do? (and when should you use it?)](https://daveceddia.com/what-does-redux-do/) and [How Redux Works: A Counter-Example](https://daveceddia.com/how-does-redux-work/) are a great intro to the basics of Redux and how to use it with React, as is this post on [React and Redux: An Introduction](http://jakesidsmith.com/blog/post/2017-11-18-redux-and-react-an-introduction/).
- Valentino Gagliardi's post [React Redux Tutorial for Beginners: Learning Redux in 2018](https://www.valentinog.com/blog/react-redux-tutorial-beginners/) is an excellent extended introduction to many aspects of using Redux.
- The CSS Tricks article [Leveling Up with React: Redux](https://css-tricks.com/learning-react-redux/) covers the Redux basics well.
- This [DevGuides: Introduction to Redux](http://devguides.io/redux/) tutorial covers several aspects of Redux, including actions, reducers, usage with React, and middleware.
### Intermediate Concepts
Once you've picked up the basics of working with actions, reducers, and the store, you may have questions about topics like working with asynchronous logic and AJAX requests, connecting a UI framework like React to your Redux store, and setting up an application to use Redux:
- The **["Advanced" docs section](https://redux.js.org/advanced)** covers working with async logic, middleware, routing.
- The Redux docs **["Learning Resources"](https://redux.js.org/introduction/learning-resources)** page points to recommended articles on a variety of Redux-related topics.
- Sophie DeBenedetto's 8-part **[Building a Simple CRUD App with React + Redux](http://www.thegreatcodeadventure.com/building-a-simple-crud-app-with-react-redux-part-1/)** series shows how to put together a basic CRUD app from scratch.
### Real-World Usage
Going from a TodoMVC app to a real production application can be a big jump, but we've got plenty of resources to help:
- Redux creator Dan Abramov's **[free "Building React Applications with Idiomatic Redux" video series](https://egghead.io/courses/building-react-applications-with-idiomatic-redux)** builds on his first video series and covers topics like middleware, routing, and persistence.
- The **[Redux FAQ](https://redux.js.org/faq)** answers many common questions about how to use Redux, and the **["Recipes" docs section](https://redux.js.org/recipes)** has information on handling derived data, testing, structuring reducer logic, and reducing boilerplate.
- Redux co-maintainer Mark Erikson's **["Practical Redux" tutorial series](http://blog.isquaredsoftware.com/series/practical-redux/)** demonstrates real-world intermediate and advanced techniques for working with React and Redux (also available as **[an interactive course on Educative.io](https://www.educative.io/collection/5687753853370368/5707702298738688)**).
- The **[React/Redux links list](https://github.com/markerikson/react-redux-links)** has categorized articles on working with [reducers and selectors](https://github.com/markerikson/react-redux-links/blob/master/redux-reducers-selectors.md), [managing side effects](https://github.com/markerikson/react-redux-links/blob/master/redux-side-effects.md), [Redux architecture and best practices](https://github.com/markerikson/react-redux-links/blob/master/redux-architecture.md), and more.
- Our community has created thousands of Redux-related libraries, addons, and tools. The **["Ecosystem" docs page](https://redux.js.org/introduction/ecosystem)** lists our recommendations, and there's a complete listing available in the **[Redux addons catalog](https://github.com/markerikson/redux-ecosystem-links)**.
- If you're looking to learn from actual application codebases, the addons catalog also has a list of **[purpose-built examples and real-world applications](https://github.com/markerikson/redux-ecosystem-links/blob/master/apps-and-examples.md)**.
Finally, Mark Erikson is teaching a series of **[Redux workshops through Workshop.me](#redux-workshops)**. Check the [workshop schedule](https://workshop.me/?a=mark) for upcoming dates and locations.
### Help and Discussion
The **[#redux channel](https://discord.gg/0ZcbPKXt5bZ6au5t)** of the **[Reactiflux Discord community](http://www.reactiflux.com)** is our official resource for all questions related to learning and using Redux. Reactiflux is a great place to hang out, ask questions, and learn - come join us!
## Before Proceeding Further
Redux is a valuable tool for organizing your state, but you should also consider whether it's appropriate for your situation. Don't use Redux just because someone said you should - take some time to understand the potential benefits and tradeoffs of using it.
Here are some suggestions on when it makes sense to use Redux:
- You have reasonable amounts of data changing over time
- You need a single source of truth for your state
- You find that keeping all your state in a top-level component is no longer sufficient
Yes, these guidelines are subjective and vague, but this is for good reason. The point at which you should integrate Redux into your application is different for every user and different for every application.
> **For more thoughts on how Redux is meant to be used, see:**
>
> - **[You Might Not Need Redux](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367)**
> - **[The Tao of Redux, Part 1 - Implementation and Intent](http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-1/)**
> - **[The Tao of Redux, Part 2 - Practice and Philosophy](http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/)**
> - **[Redux FAQ](https://redux.js.org/faq)**
## Developer Experience
Dan Abramov (author of Redux) wrote Redux while working on his React Europe talk called [“Hot Reloading with Time Travel”](https://www.youtube.com/watch?v=xsSnOQynTHs). His goal was to create a state management library with a minimal API but completely predictable behavior. Redux makes it possible to implement logging, hot reloading, time travel, universal apps, record and replay, without any buy-in from the developer.
## Influences
Redux evolves the ideas of [Flux](http://facebook.github.io/flux/), but avoids its complexity by taking cues from [Elm](https://github.com/evancz/elm-architecture-tutorial/).
Even if you haven't used Flux or Elm, Redux only takes a few minutes to get started with.
## Installation
To install the stable version:
```sh
npm install --save redux
```
This assumes you are using [npm](https://www.npmjs.com/) as your package manager.
If you're not, you can [access these files on unpkg](https://unpkg.com/redux/), download them, or point your package manager to them.
Most commonly, people consume Redux as a collection of [CommonJS](https://github.com/webpack/docs/wiki/commonjs) modules. These modules are what you get when you import `redux` in a [Webpack](https://webpack.js.org/), [Browserify](http://browserify.org/), or a Node environment. If you like to live on the edge and use [Rollup](https://rollupjs.org), we support that as well.
If you don't use a module bundler, it's also fine. The `redux` npm package includes precompiled production and development [UMD](https://github.com/umdjs/umd) builds in the [`dist` folder](https://unpkg.com/redux/dist/). They can be used directly without a bundler and are thus compatible with many popular JavaScript module loaders and environments. For example, you can drop a UMD build as a [`
redux-4.2.1/docs/Glossary.md 0000664 0000000 0000000 00000020253 14365314725 0015736 0 ustar 00root root 0000000 0000000 ---
id: glossary
title: Glossary
sidebar_label: Glossary
hide_title: true
---
# Glossary
This is a glossary of the core terms in Redux, along with their type signatures. The types are documented using [Flow notation](http://flowtype.org/docs/quick-reference.html).
## State
```js
type State = any
```
_State_ (also called the _state tree_) is a broad term, but in the Redux API it usually refers to the single state value that is managed by the store and returned by [`getState()`](api/Store.md#getState). It represents the entire state of a Redux application, which is often a deeply nested object.
By convention, the top-level state is an object or some other key-value collection like a Map, but technically it can be any type. Still, you should do your best to keep the state serializable. Don't put anything inside it that you can't easily turn into JSON.
## Action
```js
type Action = Object
```
An _action_ is a plain object that represents an intention to change the state. Actions are the only way to get data into the store. Any data, whether from UI events, network callbacks, or other sources such as WebSockets needs to eventually be dispatched as actions.
Actions must have a `type` field that indicates the type of action being performed. Types can be defined as constants and imported from another module. It's better to use strings for `type` than [Symbols](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Symbol) because strings are serializable.
Other than `type`, the structure of an action object is really up to you. If you're interested, check out [Flux Standard Action](https://github.com/acdlite/flux-standard-action) for recommendations on how actions should be constructed.
See also [async action](#async-action) below.
## Reducer
```js
type Reducer = (state: S, action: A) => S
```
A _reducer_ (also called a _reducing function_) is a function that accepts an accumulation and a value and returns a new accumulation. They are used to reduce a collection of values down to a single value.
Reducers are not unique to Redux—they are a fundamental concept in functional programming. Even most non-functional languages, like JavaScript, have a built-in API for reducing. In JavaScript, it's [`Array.prototype.reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce).
In Redux, the accumulated value is the state object, and the values being accumulated are actions. Reducers calculate a new state given the previous state and an action. They must be _pure functions_—functions that return the exact same output for given inputs. They should also be free of side-effects. This is what enables exciting features like hot reloading and time travel.
Reducers are the most important concept in Redux.
_Do not put API calls into reducers._
## Dispatching Function
```js
type BaseDispatch = (a: Action) => Action
type Dispatch = (a: Action | AsyncAction) => any
```
A _dispatching function_ (or simply _dispatch function_) is a function that accepts an action or an [async action](#async-action); it then may or may not dispatch one or more actions to the store.
We must distinguish between dispatching functions in general and the base [`dispatch`](api/Store.md#dispatchaction) function provided by the store instance without any middleware.
The base dispatch function _always_ synchronously sends an action to the store's reducer, along with the previous state returned by the store, to calculate a new state. It expects actions to be plain objects ready to be consumed by the reducer.
[Middleware](#middleware) wraps the base dispatch function. It allows the dispatch function to handle [async actions](#async-action) in addition to actions. Middleware may transform, delay, ignore, or otherwise interpret actions or async actions before passing them to the next middleware. See below for more information.
## Action Creator
```js
type ActionCreator = (...args: any) => Action | AsyncAction
```
An _action creator_ is, quite simply, a function that creates an action. Do not confuse the two terms—again, an action is a payload of information, and an action creator is a factory that creates an action.
Calling an action creator only produces an action, but does not dispatch it. You need to call the store's [`dispatch`](api/Store.md#dispatchaction) function to actually cause the mutation. Sometimes we say _bound action creators_ to mean functions that call an action creator and immediately dispatch its result to a specific store instance.
If an action creator needs to read the current state, perform an API call, or cause a side effect, like a routing transition, it should return an [async action](#async-action) instead of an action.
## Async Action
```js
type AsyncAction = any
```
An _async action_ is a value that is sent to a dispatching function, but is not yet ready for consumption by the reducer. It will be transformed by [middleware](#middleware) into an action (or a series of actions) before being sent to the base [`dispatch()`](api/Store.md#dispatchaction) function. Async actions may have different types, depending on the middleware you use. They are often asynchronous primitives, like a Promise or a thunk, which are not passed to the reducer immediately, but trigger action dispatches once an operation has completed.
## Middleware
```js
type MiddlewareAPI = { dispatch: Dispatch, getState: () => State }
type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch
```
A middleware is a higher-order function that composes a [dispatch function](#dispatching-function) to return a new dispatch function. It often turns [async actions](#async-action) into actions.
Middleware is composable using function composition. It is useful for logging actions, performing side effects like routing, or turning an asynchronous API call into a series of synchronous actions.
See [`applyMiddleware(...middlewares)`](./api/applyMiddleware.md) for a detailed look at middleware.
## Store
```js
type Store = {
dispatch: Dispatch
getState: () => State
subscribe: (listener: () => void) => () => void
replaceReducer: (reducer: Reducer) => void
}
```
A store is an object that holds the application's state tree.
There should only be a single store in a Redux app, as the composition happens on the reducer level.
- [`dispatch(action)`](api/Store.md#dispatchaction) is the base dispatch function described above.
- [`getState()`](api/Store.md#getState) returns the current state of the store.
- [`subscribe(listener)`](api/Store.md#subscribelistener) registers a function to be called on state changes.
- [`replaceReducer(nextReducer)`](api/Store.md#replacereducernextreducer) can be used to implement hot reloading and code splitting. Most likely you won't use it.
See the complete [store API reference](api/Store.md#dispatchaction) for more details.
## Store creator
```js
type StoreCreator = (reducer: Reducer, preloadedState: ?State) => Store
```
A store creator is a function that creates a Redux store. Like with dispatching function, we must distinguish the base store creator, [`createStore(reducer, preloadedState)`](api/createStore.md) exported from the Redux package, from store creators that are returned from the store enhancers.
## Store enhancer
```js
type StoreEnhancer = (next: StoreCreator) => StoreCreator
```
A store enhancer is a higher-order function that composes a store creator to return a new, enhanced store creator. This is similar to middleware in that it allows you to alter the store interface in a composable way.
Store enhancers are much the same concept as higher-order components in React, which are also occasionally called “component enhancers”.
Because a store is not an instance, but rather a plain-object collection of functions, copies can be easily created and modified without mutating the original store. There is an example in [`compose`](api/compose.md) documentation demonstrating that.
Most likely you'll never write a store enhancer, but you may use the one provided by the [developer tools](https://github.com/reduxjs/redux-devtools). It is what makes time travel possible without the app being aware it is happening. Amusingly, the [Redux middleware implementation](api/applyMiddleware.md) is itself a store enhancer.
redux-4.2.1/docs/README.md 0000664 0000000 0000000 00000006714 14365314725 0015076 0 ustar 00root root 0000000 0000000 # Table of Contents
- [Read Me](../README.md)
- [Introduction](introduction/README.md)
- [Motivation](introduction/Motivation.md)
- [Core Concepts](introduction/CoreConcepts.md)
- [Three Principles](introduction/ThreePrinciples.md)
- [Prior Art](introduction/PriorArt.md)
- [Learning Resources](introduction/LearningResources.md)
- [Ecosystem](introduction/Ecosystem.md)
- [Examples](introduction/Examples.md)
- [Basics](basics/README.md)
- [Actions](basics/Actions.md)
- [Reducers](basics/Reducers.md)
- [Store](basics/Store.md)
- [Data Flow](basics/DataFlow.md)
- [Usage with React](basics/UsageWithReact.md)
- [Example: Todo List](basics/ExampleTodoList.md)
- [Advanced](advanced/README.md)
- [Async Actions](advanced/AsyncActions.md)
- [Async Flow](advanced/AsyncFlow.md)
- [Middleware](advanced/Middleware.md)
- [Usage with React Router](advanced/UsageWithReactRouter.md)
- [Example: Reddit API](advanced/ExampleRedditAPI.md)
- [Next Steps](advanced/NextSteps.md)
- [Recipes](recipes/README.md)
- [Configuring Your Store](recipes/ConfiguringYourStore.md)
- [Migrating to Redux](recipes/MigratingToRedux.md)
- [Using Object Spread Operator](recipes/UsingObjectSpreadOperator.md)
- [Reducing Boilerplate](recipes/ReducingBoilerplate.md)
- [Server Rendering](recipes/ServerRendering.md)
- [Writing Tests](recipes/WritingTests.md)
- [Computing Derived Data](recipes/ComputingDerivedData.md)
- [Implementing Undo History](recipes/ImplementingUndoHistory.md)
- [Isolating Subapps](recipes/IsolatingSubapps.md)
- [Structuring Reducers](recipes/structuring-reducers/StructuringReducers.md)
- [Prerequisite Concepts](recipes/structuring-reducers/PrerequisiteConcepts.md)
- [Basic Reducer Structure](recipes/structuring-reducers/BasicReducerStructure.md)
- [Splitting Reducer Logic](recipes/structuring-reducers/SplittingReducerLogic.md)
- [Refactoring Reducers Example](recipes/structuring-reducers/RefactoringReducersExample.md)
- [Using `combineReducers`](recipes/structuring-reducers/UsingCombineReducers.md)
- [Beyond `combineReducers`](recipes/structuring-reducers/BeyondCombineReducers.md)
- [Normalizing State Shape](recipes/structuring-reducers/NormalizingStateShape.md)
- [Updating Normalized Data](recipes/structuring-reducers/UpdatingNormalizedData.md)
- [Reusing Reducer Logic](recipes/structuring-reducers/ReusingReducerLogic.md)
- [Immutable Update Patterns](recipes/structuring-reducers/ImmutableUpdatePatterns.md)
- [Initializing State](recipes/structuring-reducers/InitializingState.md)
- [Using Immutable.JS with Redux](recipes/UsingImmutableJS.md)
- [FAQ](FAQ.md)
- [General](faq/General.md)
- [Reducers](faq/Reducers.md)
- [Organizing State](faq/OrganizingState.md)
- [Store Setup](faq/StoreSetup.md)
- [Actions](faq/Actions.md)
- [Immutable Data](faq/ImmutableData.md)
- [Code Structure](faq/CodeStructure.md)
- [Performance](faq/Performance.md)
- [Design Decisions](faq/DesignDecisions.md)
- [React Redux](faq/ReactRedux.md)
- [Miscellaneous](faq/Miscellaneous.md)
- [Troubleshooting](Troubleshooting.md)
- [Glossary](Glossary.md)
- [API Reference](api/README.md)
- [createStore](api/createStore.md)
- [Store](api/Store.md)
- [combineReducers](api/combineReducers.md)
- [applyMiddleware](api/applyMiddleware.md)
- [bindActionCreators](api/bindActionCreators.md)
- [compose](api/compose.md)
- [Change Log](../CHANGELOG.md)
- [Patrons](../PATRONS.md)
- [Feedback](Feedback.md)
redux-4.2.1/docs/Troubleshooting.md 0000664 0000000 0000000 00000015163 14365314725 0017326 0 ustar 00root root 0000000 0000000 ---
id: troubleshooting
title: Troubleshooting
sidebar_label: Troubleshooting
hide_title: true
---
# Troubleshooting
This is a place to share common problems and solutions to them.
The examples use React, but you should still find them useful if you use something else.
### Nothing happens when I dispatch an action
Sometimes, you are trying to dispatch an action, but your view does not update. Why does this happen? There may be several reasons for this.
#### Never mutate reducer arguments
It is tempting to modify the `state` or `action` passed to you by Redux. Don't do this!
Redux assumes that you never mutate the objects it gives to you in the reducer. **Every single time, you must return the new state object.** Even if you don't use a library like [Immutable](https://facebook.github.io/immutable-js/), you need to completely avoid mutation.
Immutability is what lets [react-redux](https://github.com/gaearon/react-redux) efficiently subscribe to fine-grained updates of your state. It also enables great developer experience features such as time travel with [redux-devtools](http://github.com/reduxjs/redux-devtools).
For example, a reducer like this is wrong because it mutates the state:
```js
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
// Wrong! This mutates state
state.push({
text: action.text,
completed: false,
})
return state
case 'COMPLETE_TODO':
// Wrong! This mutates state[action.index].
state[action.index].completed = true
return state
default:
return state
}
}
```
It needs to be rewritten like this:
```js
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
// Return a new array
return [
...state,
{
text: action.text,
completed: false,
},
]
case 'COMPLETE_TODO':
// Return a new array
return state.map((todo, index) => {
if (index === action.index) {
// Copy the object before mutating
return Object.assign({}, todo, {
completed: true,
})
}
return todo
})
default:
return state
}
}
```
It's more code, but it's exactly what makes Redux predictable and efficient. If you want to have less code, you can use a helper like [`React.addons.update`](https://facebook.github.io/react/docs/update.html) to write immutable transformations with a terse syntax:
```js
// Before:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: true,
})
}
return todo
})
// After
return update(state, {
[action.index]: {
completed: {
$set: true,
},
},
})
```
Finally, to update objects, you'll need something like `_.extend` from Underscore, or better, an [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) polyfill.
Make sure that you use `Object.assign` correctly. For example, instead of returning something like `Object.assign(state, newData)` from your reducers, return `Object.assign({}, state, newData)`. This way you don't override the previous `state`.
You can also enable the [object spread operator proposal](recipes/UsingObjectSpreadOperator.md) for a more succinct syntax:
```js
// Before:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: true,
})
}
return todo
})
// After:
return state.map((todo, index) => {
if (index === action.index) {
return { ...todo, completed: true }
}
return todo
})
```
Note that experimental language features are subject to change.
Also keep an eye out for nested state objects that need to be deeply copied. Both `_.extend` and `Object.assign` make a shallow copy of the state. See [Updating Nested Objects](./recipes/structuring-reducers/ImmutableUpdatePatterns.md#updating-nested-objects) for suggestions on how to deal with nested state objects.
#### Don't forget to call [`dispatch(action)`](api/Store.md#dispatchaction)
If you define an action creator, calling it will _not_ automatically dispatch the action. For example, this code will do nothing:
#### `TodoActions.js`
```js
export function addTodo(text) {
return { type: 'ADD_TODO', text }
}
```
#### `AddTodo.js`
```js
import React, { Component } from 'react'
import { addTodo } from './TodoActions'
class AddTodo extends Component {
handleClick() {
// Won't work!
addTodo('Fix the issue')
}
render() {
return
}
}
```
It doesn't work because your action creator is just a function that _returns_ an action. It is up to you to actually dispatch it. We can't bind your action creators to a particular Store instance during the definition because apps that render on the server need a separate Redux store for every request.
The fix is to call [`dispatch()`](api/Store.md#dispatchaction) method on the [store](api/Store.md) instance:
```js
handleClick() {
// Works! (but you need to grab store somehow)
store.dispatch(addTodo('Fix the issue'))
}
```
If you're somewhere deep in the component hierarchy, it is cumbersome to pass the store down manually. This is why [react-redux](https://github.com/gaearon/react-redux) lets you use a `connect` [higher-order component](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750) that will, apart from subscribing you to a Redux store, inject `dispatch` into your component's props.
The fixed code looks like this:
#### `AddTodo.js`
```js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { addTodo } from './TodoActions'
class AddTodo extends Component {
handleClick() {
// Works!
this.props.dispatch(addTodo('Fix the issue'))
}
render() {
return
}
}
// In addition to the state, `connect` puts `dispatch` in our props.
export default connect()(AddTodo)
```
You can then pass `dispatch` down to other components manually, if you want to.
#### Make sure mapStateToProps is correct
It's possible you're correctly dispatching an action and applying your reducer but the corresponding state is not being correctly translated into props.
## Something else doesn't work
Ask around on the **#redux** [Reactiflux](http://reactiflux.com/) Discord channel, or [create an issue](https://github.com/reduxjs/redux/issues).
If you figure it out, [edit this document](https://github.com/reduxjs/redux/edit/master/docs/Troubleshooting.md) as a courtesy to the next person having the same problem.
redux-4.2.1/docs/advanced/ 0000775 0000000 0000000 00000000000 14365314725 0015354 5 ustar 00root root 0000000 0000000 redux-4.2.1/docs/advanced/AsyncActions.md 0000664 0000000 0000000 00000050260 14365314725 0020277 0 ustar 00root root 0000000 0000000 ---
id: async-actions
title: Async Actions
sidebar_label: Async Actions
hide_title: true
---
# Async Actions
In the [basics guide](../basics/README.md), we built a simple todo application. It was fully synchronous. Every time an action was dispatched, the state was updated immediately.
In this guide, we will build a different, asynchronous application. It will use the Reddit API to show the current headlines for a selected subreddit. How does asynchronicity fit into Redux flow?
## Actions
When you call an asynchronous API, there are two crucial moments in time: the moment you start the call, and the moment when you receive an answer (or a timeout).
Each of these two moments usually require a change in the application state; to do that, you need to dispatch normal actions that will be processed by reducers synchronously. Usually, for any API request you'll want to dispatch at least three different kinds of actions:
- **An action informing the reducers that the request began.**
The reducers may handle this action by toggling an `isFetching` flag in the state. This way the UI knows it's time to show a spinner.
- **An action informing the reducers that the request finished successfully.**
The reducers may handle this action by merging the new data into the state they manage and resetting `isFetching`. The UI would hide the spinner, and display the fetched data.
- **An action informing the reducers that the request failed.**
The reducers may handle this action by resetting `isFetching`. Additionally, some reducers may want to store the error message so the UI can display it.
You may use a dedicated `status` field in your actions:
```js
{ type: 'FETCH_POSTS' }
{ type: 'FETCH_POSTS', status: 'error', error: 'Oops' }
{ type: 'FETCH_POSTS', status: 'success', response: { ... } }
```
Or you can define separate types for them:
```js
{ type: 'FETCH_POSTS_REQUEST' }
{ type: 'FETCH_POSTS_FAILURE', error: 'Oops' }
{ type: 'FETCH_POSTS_SUCCESS', response: { ... } }
```
Choosing whether to use a single action type with flags, or multiple action types, is up to you. It's a convention you need to decide with your team. Multiple types leave less room for a mistake, but this is not an issue if you generate action creators and reducers with a helper library like [redux-actions](https://redux-actions.js.org/).
Whatever convention you choose, stick with it throughout the application.
We'll use separate types in this tutorial.
## Synchronous Action Creators
Let's start by defining the several synchronous action types and action creators we need in our example app. Here, the user can select a subreddit to display:
#### `actions.js` (Synchronous)
```js
export const SELECT_SUBREDDIT = 'SELECT_SUBREDDIT'
export function selectSubreddit(subreddit) {
return {
type: SELECT_SUBREDDIT,
subreddit,
}
}
```
They can also press a “refresh” button to update it:
```js
export const INVALIDATE_SUBREDDIT = 'INVALIDATE_SUBREDDIT'
export function invalidateSubreddit(subreddit) {
return {
type: INVALIDATE_SUBREDDIT,
subreddit,
}
}
```
These were the actions governed by the user interaction. We will also have another kind of action, governed by the network requests. We will see how to dispatch them later, but for now, we just want to define them.
When it's time to fetch the posts for some subreddit, we will dispatch a `REQUEST_POSTS` action:
```js
export const REQUEST_POSTS = 'REQUEST_POSTS'
function requestPosts(subreddit) {
return {
type: REQUEST_POSTS,
subreddit,
}
}
```
It is important for it to be separate from `SELECT_SUBREDDIT` or `INVALIDATE_SUBREDDIT`. While they may occur one after another, as the app grows more complex, you might want to fetch some data independently of the user action (for example, to prefetch the most popular subreddits, or to refresh stale data once in a while). You may also want to fetch in response to a route change, so it's not wise to couple fetching to some particular UI event early on.
Finally, when the network request comes through, we will dispatch `RECEIVE_POSTS`:
```js
export const RECEIVE_POSTS = 'RECEIVE_POSTS'
function receivePosts(subreddit, json) {
return {
type: RECEIVE_POSTS,
subreddit,
posts: json.data.children.map((child) => child.data),
receivedAt: Date.now(),
}
}
```
This is all we need to know for now. The particular mechanism to dispatch these actions together with network requests will be discussed later.
> ##### Note on Error Handling
>
> In a real app, you'd also want to dispatch an action on request failure. We won't implement error handling in this tutorial, but the [real world example](../introduction/Examples.md#real-world) shows one of the possible approaches.
## Designing the State Shape
Just like in the basic tutorial, you'll need to [design the shape of your application's state](../basics/Reducers.md#designing-the-state-shape) before rushing into the implementation. With asynchronous code, there is more state to take care of, so we need to think it through.
This part is often confusing to beginners, because it is not immediately clear what information describes the state of an asynchronous application, and how to organize it in a single tree.
We'll start with the most common use case: lists. Web applications often show lists of things. For example, a list of posts, or a list of friends. You'll need to figure out what sorts of lists your app can show. You want to store them separately in the state, because this way you can cache them and only fetch again if necessary.
Here's what the state shape for our “Reddit headlines” app might look like:
```js
{
selectedSubreddit: 'frontend',
postsBySubreddit: {
frontend: {
isFetching: true,
didInvalidate: false,
items: []
},
reactjs: {
isFetching: false,
didInvalidate: false,
lastUpdated: 1439478405547,
items: [
{
id: 42,
title: 'Confusion about Flux and Relay'
},
{
id: 500,
title: 'Creating a Simple Application Using React JS and Flux Architecture'
}
]
}
}
}
```
There are a few important bits here:
- We store each subreddit's information separately so we can cache every subreddit. When the user switches between them the second time, the update will be instant, and we won't need to refetch unless we want to. Don't worry about all these items being in memory: unless you're dealing with tens of thousands of items, and your user rarely closes the tab, you won't need any sort of cleanup.
- For every list of items, you'll want to store `isFetching` to show a spinner, `didInvalidate` so you can later toggle it when the data is stale, `lastUpdated` so you know when it was fetched the last time, and the `items` themselves. In a real app, you'll also want to store pagination state like `fetchedPageCount` and `nextPageUrl`.
> ##### Note on Nested Entities
>
> In this example, we store the received items together with the pagination information. However, this approach won't work well if you have nested entities referencing each other, or if you let the user edit items. Imagine the user wants to edit a fetched post, but this post is duplicated in several places in the state tree. This would be really painful to implement.
>
> If you have nested entities, or if you let users edit received entities, you should keep them separately in the state as if it was a database. In pagination information, you would only refer to them by their IDs. This lets you always keep them up to date. The [real world example](../introduction/Examples.md#real-world) shows this approach, together with [normalizr](https://github.com/paularmstrong/normalizr) to normalize the nested API responses. With this approach, your state might look like this:
>
> ```js
> {
> selectedSubreddit: 'frontend',
> entities: {
> users: {
> 2: {
> id: 2,
> name: 'Andrew'
> }
> },
> posts: {
> 42: {
> id: 42,
> title: 'Confusion about Flux and Relay',
> author: 2
> },
> 100: {
> id: 100,
> title: 'Creating a Simple Application Using React JS and Flux Architecture',
> author: 2
> }
> }
> },
> postsBySubreddit: {
> frontend: {
> isFetching: true,
> didInvalidate: false,
> items: []
> },
> reactjs: {
> isFetching: false,
> didInvalidate: false,
> lastUpdated: 1439478405547,
> items: [ 42, 100 ]
> }
> }
> }
> ```
>
> In this guide, we won't normalize entities, but it's something you should consider for a more dynamic application.
## Handling Actions
Before going into the details of dispatching actions together with network requests, we will write the reducers for the actions we defined above.
> ##### Note on Reducer Composition
>
> Here, we assume that you understand reducer composition with [`combineReducers()`](../api/combineReducers.md), as described in the [Splitting Reducers](../basics/Reducers.md#splitting-reducers) section on the [basics guide](../basics/README.md). If you don't, please [read it first](../basics/Reducers.md#splitting-reducers).
#### `reducers.js`
```js
import { combineReducers } from 'redux'
import {
SELECT_SUBREDDIT,
INVALIDATE_SUBREDDIT,
REQUEST_POSTS,
RECEIVE_POSTS,
} from '../actions'
function selectedSubreddit(state = 'reactjs', action) {
switch (action.type) {
case SELECT_SUBREDDIT:
return action.subreddit
default:
return state
}
}
function posts(
state = {
isFetching: false,
didInvalidate: false,
items: [],
},
action
) {
switch (action.type) {
case INVALIDATE_SUBREDDIT:
return Object.assign({}, state, {
didInvalidate: true,
})
case REQUEST_POSTS:
return Object.assign({}, state, {
isFetching: true,
didInvalidate: false,
})
case RECEIVE_POSTS:
return Object.assign({}, state, {
isFetching: false,
didInvalidate: false,
items: action.posts,
lastUpdated: action.receivedAt,
})
default:
return state
}
}
function postsBySubreddit(state = {}, action) {
switch (action.type) {
case INVALIDATE_SUBREDDIT:
case RECEIVE_POSTS:
case REQUEST_POSTS:
return Object.assign({}, state, {
[action.subreddit]: posts(state[action.subreddit], action),
})
default:
return state
}
}
const rootReducer = combineReducers({
postsBySubreddit,
selectedSubreddit,
})
export default rootReducer
```
In this code, there are two interesting parts:
- We use ES6 computed property syntax so we can update `state[action.subreddit]` with `Object.assign()` in a concise way. This:
```js
return Object.assign({}, state, {
[action.subreddit]: posts(state[action.subreddit], action),
})
```
is equivalent to this:
```js
let nextState = {}
nextState[action.subreddit] = posts(state[action.subreddit], action)
return Object.assign({}, state, nextState)
```
- We extracted `posts(state, action)` that manages the state of a specific post list. This is just [reducer composition](../basics/Reducers.md#splitting-reducers)! It is our choice how to split the reducer into smaller reducers, and in this case, we're delegating updating items inside an object to a `posts` reducer. The [real world example](../introduction/Examples.md#real-world) goes even further, showing how to create a reducer factory for parameterized pagination reducers.
Remember that reducers are just functions, so you can use functional composition and higher-order functions as much as you feel comfortable.
## Async Action Creators
Finally, how do we use the synchronous action creators we [defined earlier](#synchronous-action-creators) together with network requests? The standard way to do it with Redux is to use the [Redux Thunk middleware](https://github.com/gaearon/redux-thunk). It comes in a separate package called `redux-thunk`. We'll explain how middleware works in general [later](Middleware.md); for now, there is just one important thing you need to know: by using this specific middleware, an action creator can return a function instead of an action object. This way, the action creator becomes a [thunk](https://en.wikipedia.org/wiki/Thunk).
When an action creator returns a function, that function will get executed by the Redux Thunk middleware. This function doesn't need to be pure; it is thus allowed to have side effects, including executing asynchronous API calls. The function can also dispatch actions—like those synchronous actions we defined earlier.
We can still define these special thunk action creators inside our `actions.js` file:
#### `actions.js` (Asynchronous)
```js
import fetch from 'cross-fetch'
export const REQUEST_POSTS = 'REQUEST_POSTS'
function requestPosts(subreddit) {
return {
type: REQUEST_POSTS,
subreddit,
}
}
export const RECEIVE_POSTS = 'RECEIVE_POSTS'
function receivePosts(subreddit, json) {
return {
type: RECEIVE_POSTS,
subreddit,
posts: json.data.children.map((child) => child.data),
receivedAt: Date.now(),
}
}
export const INVALIDATE_SUBREDDIT = 'INVALIDATE_SUBREDDIT'
export function invalidateSubreddit(subreddit) {
return {
type: INVALIDATE_SUBREDDIT,
subreddit,
}
}
// Meet our first thunk action creator!
// Though its insides are different, you would use it just like any other action creator:
// store.dispatch(fetchPosts('reactjs'))
export function fetchPosts(subreddit) {
// Thunk middleware knows how to handle functions.
// It passes the dispatch method as an argument to the function,
// thus making it able to dispatch actions itself.
return function (dispatch) {
// First dispatch: the app state is updated to inform
// that the API call is starting.
dispatch(requestPosts(subreddit))
// The function called by the thunk middleware can return a value,
// that is passed on as the return value of the dispatch method.
// In this case, we return a promise to wait for.
// This is not required by thunk middleware, but it is convenient for us.
return fetch(`https://www.reddit.com/r/${subreddit}.json`)
.then(
(response) => response.json(),
// Do not use catch, because that will also catch
// any errors in the dispatch and resulting render,
// causing a loop of 'Unexpected batch number' errors.
// https://github.com/facebook/react/issues/6895
(error) => console.log('An error occurred.', error)
)
.then((json) =>
// We can dispatch many times!
// Here, we update the app state with the results of the API call.
dispatch(receivePosts(subreddit, json))
)
}
}
```
> ##### Note on `fetch`
>
> We use [`fetch` API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API) in the examples. It is a new API for making network requests that replaces `XMLHttpRequest` for most common needs. Because most browsers don't yet support it natively, we suggest that you use [`cross-fetch`](https://github.com/lquixada/cross-fetch) library:
>
> ```js
> // Do this in every file where you use `fetch`
> import fetch from 'cross-fetch'
> ```
>
> Internally, it uses [`whatwg-fetch` polyfill](https://github.com/github/fetch) on the client, and [`node-fetch`](https://github.com/bitinn/node-fetch) on the server, so you won't need to change API calls if you change your app to be [universal](https://medium.com/@mjackson/universal-javascript-4761051b7ae9).
>
> Be aware that any `fetch` polyfill assumes a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) polyfill is already present. The easiest way to ensure you have a Promise polyfill is to enable Babel's ES6 polyfill in your entry point before any other code runs:
>
> ```js
> // Do this once before any other code in your app
> import 'babel-polyfill'
> ```
How do we include the Redux Thunk middleware in the dispatch mechanism? We use the [`applyMiddleware()`](../api/applyMiddleware.md) store enhancer from Redux, as shown below:
#### `index.js`
```js
import thunkMiddleware from 'redux-thunk'
import { createLogger } from 'redux-logger'
import { createStore, applyMiddleware } from 'redux'
import { selectSubreddit, fetchPosts } from './actions'
import rootReducer from './reducers'
const loggerMiddleware = createLogger()
const store = createStore(
rootReducer,
applyMiddleware(
thunkMiddleware, // lets us dispatch() functions
loggerMiddleware // neat middleware that logs actions
)
)
store.dispatch(selectSubreddit('reactjs'))
store.dispatch(fetchPosts('reactjs')).then(() => console.log(store.getState()))
```
The nice thing about thunks is that they can dispatch results of each other:
#### `actions.js` (with `fetch`)
```js
import fetch from 'cross-fetch'
export const REQUEST_POSTS = 'REQUEST_POSTS'
function requestPosts(subreddit) {
return {
type: REQUEST_POSTS,
subreddit,
}
}
export const RECEIVE_POSTS = 'RECEIVE_POSTS'
function receivePosts(subreddit, json) {
return {
type: RECEIVE_POSTS,
subreddit,
posts: json.data.children.map((child) => child.data),
receivedAt: Date.now(),
}
}
export const INVALIDATE_SUBREDDIT = 'INVALIDATE_SUBREDDIT'
export function invalidateSubreddit(subreddit) {
return {
type: INVALIDATE_SUBREDDIT,
subreddit,
}
}
function fetchPosts(subreddit) {
return (dispatch) => {
dispatch(requestPosts(subreddit))
return fetch(`https://www.reddit.com/r/${subreddit}.json`)
.then((response) => response.json())
.then((json) => dispatch(receivePosts(subreddit, json)))
}
}
function shouldFetchPosts(state, subreddit) {
const posts = state.postsBySubreddit[subreddit]
if (!posts) {
return true
} else if (posts.isFetching) {
return false
} else {
return posts.didInvalidate
}
}
export function fetchPostsIfNeeded(subreddit) {
// Note that the function also receives getState()
// which lets you choose what to dispatch next.
// This is useful for avoiding a network request if
// a cached value is already available.
return (dispatch, getState) => {
if (shouldFetchPosts(getState(), subreddit)) {
// Dispatch a thunk from thunk!
return dispatch(fetchPosts(subreddit))
} else {
// Let the calling code know there's nothing to wait for.
return Promise.resolve()
}
}
}
```
This lets us write more sophisticated async control flow gradually, while the consuming code can stay pretty much the same:
#### `index.js`
```js
store
.dispatch(fetchPostsIfNeeded('reactjs'))
.then(() => console.log(store.getState()))
```
> ##### Note about Server Rendering
>
> Async action creators are especially convenient for server rendering. You can create a store, dispatch a single async action creator that dispatches other async action creators to fetch data for a whole section of your app, and only render after the Promise it returns, completes. Then your store will already be hydrated with the state you need before rendering.
[Thunk middleware](https://github.com/gaearon/redux-thunk) isn't the only way to orchestrate asynchronous actions in Redux:
- You can use [redux-promise](https://github.com/acdlite/redux-promise) or [redux-promise-middleware](https://github.com/pburtchaell/redux-promise-middleware) to dispatch Promises instead of functions.
- You can use [redux-observable](https://github.com/redux-observable/redux-observable) to dispatch Observables.
- You can use the [redux-saga](https://github.com/yelouafi/redux-saga/) middleware to build more complex asynchronous actions.
- You can use the [redux-pack](https://github.com/lelandrichardson/redux-pack) middleware to dispatch promise-based asynchronous actions.
- You can even write a custom middleware to describe calls to your API, like the [real world example](../introduction/Examples.md#real-world) does.
It is up to you to try a few options, choose a convention you like, and follow it, whether with, or without the middleware.
## Connecting to UI
Dispatching async actions is no different from dispatching synchronous actions, so we won't discuss this in detail. See [Usage with React](../basics/UsageWithReact.md) for an introduction into using Redux from React components. See [Example: Reddit API](ExampleRedditAPI.md) for the complete source code discussed in this example.
## Next Steps
Read [Async Flow](AsyncFlow.md) to recap how async actions fit into the Redux flow.
redux-4.2.1/docs/advanced/AsyncFlow.md 0000664 0000000 0000000 00000003043 14365314725 0017603 0 ustar 00root root 0000000 0000000 ---
id: async-flow
title: Async Flow
sidebar_label: Async Flow
hide_title: true
---
# Async Flow
Without [middleware](Middleware.md), Redux store only supports [synchronous data flow](../basics/DataFlow.md). This is what you get by default with [`createStore()`](../api/createStore.md).
You may enhance [`createStore()`](../api/createStore.md) with [`applyMiddleware()`](../api/applyMiddleware.md). It is not required, but it lets you [express asynchronous actions in a convenient way](AsyncActions.md).
Asynchronous middleware like [redux-thunk](https://github.com/gaearon/redux-thunk) or [redux-promise](https://github.com/acdlite/redux-promise) wraps the store's [`dispatch()`](../api/Store.md#dispatchaction) method and allows you to dispatch something other than actions, for example, functions or Promises. Any middleware you use can then intercept anything you dispatch, and in turn, can pass actions to the next middleware in the chain. For example, a Promise middleware can intercept Promises and dispatch a pair of begin/end actions asynchronously in response to each Promise.
When the last middleware in the chain dispatches an action, it has to be a plain object. This is when the [synchronous Redux data flow](../basics/DataFlow.md) takes place.
Check out [the full source code for the async example](ExampleRedditAPI.md).
## Next Steps
Now that you've seen an example of what middleware can do in Redux, it's time to learn how it actually works, and how you can create your own. Go on to the next detailed section about [Middleware](Middleware.md).
redux-4.2.1/docs/advanced/ExampleRedditAPI.md 0000664 0000000 0000000 00000017576 14365314725 0020777 0 ustar 00root root 0000000 0000000 ---
id: example-reddit-api
title: Example: Reddit API
sidebar_label: Example: Reddit API
hide_title: true
---
# Example: Reddit API
This is the complete source code of the Reddit headline fetching example we built during the [advanced tutorial](README.md).
## Entry Point
#### `index.js`
```js
import 'babel-polyfill'
import React from 'react'
import { render } from 'react-dom'
import Root from './containers/Root'
render(Loading...
}
{!isFetching && posts.length === 0 && Empty.
}
{posts.length > 0 && (
{value}
)
}
}
Picker.propTypes = {
options: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
}
```
#### `components/Posts.js`
```js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class Posts extends Component {
render() {
return (
{this.props.posts.map((post, i) => (
)
}
}
Posts.propTypes = {
posts: PropTypes.array.isRequired,
}
```
redux-4.2.1/docs/advanced/Middleware.md 0000664 0000000 0000000 00000042346 14365314725 0017764 0 ustar 00root root 0000000 0000000 ---
id: middleware
title: Middleware
sidebar_label: Middleware
hide_title: true
---
# Middleware
You've seen middleware in action in the [Async Actions](../advanced/AsyncActions.md) example. If you've used server-side libraries like [Express](http://expressjs.com/) and [Koa](http://koajs.com/), you were also probably already familiar with the concept of _middleware_. In these frameworks, middleware is some code you can put between the framework receiving a request, and the framework generating a response. For example, Express or Koa middleware may add CORS headers, logging, compression, and more. The best feature of middleware is that it's composable in a chain. You can use multiple independent third-party middleware in a single project.
Redux middleware solves different problems than Express or Koa middleware, but in a conceptually similar way. **It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer.** People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more.
This article is divided into an in-depth intro to help you grok the concept, and [a few practical examples](#seven-examples) to show the power of middleware at the very end. You may find it helpful to switch back and forth between them, as you flip between feeling bored and inspired.
## Understanding Middleware
While middleware can be used for a variety of things, including asynchronous API calls, it's really important that you understand where it comes from. We'll guide you through the thought process leading to middleware, by using logging and crash reporting as examples.
### Problem: Logging
One of the benefits of Redux is that it makes state changes predictable and transparent. Every time an action is dispatched, the new state is computed and saved. The state cannot change by itself, it can only change as a consequence of a specific action.
Wouldn't it be nice if we logged every action that happens in the app, together with the state computed after it? When something goes wrong, we can look back at our log, and figure out which action corrupted the state.
How do we approach this with Redux?
### Attempt #1: Logging Manually
The most naïve solution is just to log the action and the next state yourself every time you call [`store.dispatch(action)`](../api/Store.md#dispatchaction). It's not really a solution, but just a first step towards understanding the problem.
> ##### Note
>
> If you're using [react-redux](https://github.com/reduxjs/react-redux) or similar bindings, you likely won't have direct access to the store instance in your components. For the next few paragraphs, just assume you pass the store down explicitly.
Say, you call this when creating a todo:
```js
store.dispatch(addTodo('Use Redux'))
```
To log the action and state, you can change it to something like this:
```js
const action = addTodo('Use Redux')
console.log('dispatching', action)
store.dispatch(action)
console.log('next state', store.getState())
```
This produces the desired effect, but you wouldn't want to do it every time.
### Attempt #2: Wrapping Dispatch
You can extract logging into a function:
```js
function dispatchAndLog(store, action) {
console.log('dispatching', action)
store.dispatch(action)
console.log('next state', store.getState())
}
```
You can then use it everywhere instead of `store.dispatch()`:
```js
dispatchAndLog(store, addTodo('Use Redux'))
```
We could end this here, but it's not very convenient to import a special function every time.
### Attempt #3: Monkeypatching Dispatch
What if we just replace the `dispatch` function on the store instance? The Redux store is just a plain object with [a few methods](../api/Store.md), and we're writing JavaScript, so we can just monkeypatch the `dispatch` implementation:
```js
const next = store.dispatch
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
```
This is already closer to what we want! No matter where we dispatch an action, it is guaranteed to be logged. Monkeypatching never feels right, but we can live with this for now.
### Problem: Crash Reporting
What if we want to apply **more than one** such transformation to `dispatch`?
A different useful transformation that comes to my mind is reporting JavaScript errors in production. The global `window.onerror` event is not reliable because it doesn't provide stack information in some older browsers, which is crucial to understand why an error is happening.
Wouldn't it be useful if, any time an error is thrown as a result of dispatching an action, we would send it to a crash reporting service like [Sentry](https://getsentry.com/welcome/) with the stack trace, the action that caused the error, and the current state? This way it's much easier to reproduce the error in development.
However, it is important that we keep logging and crash reporting separate. Ideally we want them to be different modules, potentially in different packages. Otherwise we can't have an ecosystem of such utilities. (Hint: we're slowly getting to what middleware is!)
If logging and crash reporting are separate utilities, they might look like this:
```js
function patchStoreToAddLogging(store) {
const next = store.dispatch
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
}
function patchStoreToAddCrashReporting(store) {
const next = store.dispatch
store.dispatch = function dispatchAndReportErrors(action) {
try {
return next(action)
} catch (err) {
console.error('Caught an exception!', err)
Raven.captureException(err, {
extra: {
action,
state: store.getState(),
},
})
throw err
}
}
}
```
If these functions are published as separate modules, we can later use them to patch our store:
```js
patchStoreToAddLogging(store)
patchStoreToAddCrashReporting(store)
```
Still, this isn't nice.
### Attempt #4: Hiding Monkeypatching
Monkeypatching is a hack. “Replace any method you like”, what kind of API is that? Let's figure out the essence of it instead. Previously, our functions replaced `store.dispatch`. What if they _returned_ the new `dispatch` function instead?
```js
function logger(store) {
const next = store.dispatch
// Previously:
// store.dispatch = function dispatchAndLog(action) {
return function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
}
```
We could provide a helper inside Redux that would apply the actual monkeypatching as an implementation detail:
```js
function applyMiddlewareByMonkeypatching(store, middlewares) {
middlewares = middlewares.slice()
middlewares.reverse()
// Transform dispatch function with each middleware.
middlewares.forEach((middleware) => (store.dispatch = middleware(store)))
}
```
We could use it to apply multiple middleware like this:
```js
applyMiddlewareByMonkeypatching(store, [logger, crashReporter])
```
However, it is still monkeypatching.
The fact that we hide it inside the library doesn't alter this fact.
### Attempt #5: Removing Monkeypatching
Why do we even overwrite `dispatch`? Of course, to be able to call it later, but there's also another reason: so that every middleware can access (and call) the previously wrapped `store.dispatch`:
```js
function logger(store) {
// Must point to the function returned by the previous middleware:
const next = store.dispatch
return function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
}
```
It is essential to chaining middleware!
If `applyMiddlewareByMonkeypatching` doesn't assign `store.dispatch` immediately after processing the first middleware, `store.dispatch` will keep pointing to the original `dispatch` function. Then the second middleware will also be bound to the original `dispatch` function.
But there's also a different way to enable chaining. The middleware could accept the `next()` dispatch function as a parameter instead of reading it from the `store` instance.
```js
function logger(store) {
return function wrapDispatchToAddLogging(next) {
return function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
}
}
```
It's a [“we need to go deeper”](http://knowyourmeme.com/memes/we-need-to-go-deeper) kind of moment, so it might take a while for this to make sense. The function cascade feels intimidating. ES6 arrow functions make this [currying](https://en.wikipedia.org/wiki/Currying) easier on eyes:
```js
const logger = (store) => (next) => (action) => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
const crashReporter = (store) => (next) => (action) => {
try {
return next(action)
} catch (err) {
console.error('Caught an exception!', err)
Raven.captureException(err, {
extra: {
action,
state: store.getState(),
},
})
throw err
}
}
```
**This is exactly what Redux middleware looks like.**
Now middleware takes the `next()` dispatch function, and returns a dispatch function, which in turn serves as `next()` to the middleware to the left, and so on. It's still useful to have access to some store methods like `getState()`, so `store` stays available as the top-level argument.
### Attempt #6: Naïvely Applying the Middleware
Instead of `applyMiddlewareByMonkeypatching()`, we could write `applyMiddleware()` that first obtains the final, fully wrapped `dispatch()` function, and returns a copy of the store using it:
```js
// Warning: Naïve implementation!
// That's *not* Redux API.
function applyMiddleware(store, middlewares) {
middlewares = middlewares.slice()
middlewares.reverse()
let dispatch = store.dispatch
middlewares.forEach((middleware) => (dispatch = middleware(store)(dispatch)))
return Object.assign({}, store, { dispatch })
}
```
The implementation of [`applyMiddleware()`](../api/applyMiddleware.md) that ships with Redux is similar, but **different in three important aspects**:
- It only exposes a subset of the [store API](../api/Store.md) to the middleware: [`dispatch(action)`](../api/Store.md#dispatchaction) and [`getState()`](../api/Store.md#getState).
- It does a bit of trickery to make sure that if you call `store.dispatch(action)` from your middleware instead of `next(action)`, the action will actually travel the whole middleware chain again, including the current middleware. This is useful for asynchronous middleware, as we have seen [previously](AsyncActions.md). There is one caveat when calling `dispatch` during setup, described below.
- To ensure that you may only apply middleware once, it operates on `createStore()` rather than on `store` itself. Instead of `(store, middlewares) => store`, its signature is `(...middlewares) => (createStore) => createStore`.
Because it is cumbersome to apply functions to `createStore()` before using it, `createStore()` accepts an optional last argument to specify such functions.
#### Caveat: Dispatching During Setup
While `applyMiddleware` executes and sets up your middleware, the `store.dispatch` function will point to the vanilla version provided by `createStore`. Dispatching would result in no other middleware being applied. If you are expecting an interaction with another middleware during setup, you will probably be disappointed. Because of this unexpected behavior, `applyMiddleware` will throw an error if you try to dispatch an action before the set up completes. Instead, you should either communicate directly with that other middleware via a common object (for an API-calling middleware, this may be your API client object) or waiting until after the middleware is constructed with a callback.
### The Final Approach
Given this middleware we just wrote:
```js
const logger = (store) => (next) => (action) => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
const crashReporter = (store) => (next) => (action) => {
try {
return next(action)
} catch (err) {
console.error('Caught an exception!', err)
Raven.captureException(err, {
extra: {
action,
state: store.getState(),
},
})
throw err
}
}
```
Here's how to apply it to a Redux store:
```js
import { createStore, combineReducers, applyMiddleware } from 'redux'
const todoApp = combineReducers(reducers)
const store = createStore(
todoApp,
// applyMiddleware() tells createStore() how to handle middleware
applyMiddleware(logger, crashReporter)
)
```
That's it! Now any actions dispatched to the store instance will flow through `logger` and `crashReporter`:
```js
// Will flow through both logger and crashReporter middleware!
store.dispatch(addTodo('Use Redux'))
```
## Seven Examples
If your head boiled from reading the above section, imagine what it was like to write it. This section is meant to be a relaxation for you and me, and will help get your gears turning.
Each function below is a valid Redux middleware. They are not equally useful, but at least they are equally fun.
```js
/**
* Logs all actions and states after they are dispatched.
*/
const logger = (store) => (next) => (action) => {
console.group(action.type)
console.info('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
console.groupEnd()
return result
}
/**
* Sends crash reports as state is updated and listeners are notified.
*/
const crashReporter = (store) => (next) => (action) => {
try {
return next(action)
} catch (err) {
console.error('Caught an exception!', err)
Raven.captureException(err, {
extra: {
action,
state: store.getState(),
},
})
throw err
}
}
/**
* Schedules actions with { meta: { delay: N } } to be delayed by N milliseconds.
* Makes `dispatch` return a function to cancel the timeout in this case.
*/
const timeoutScheduler = (store) => (next) => (action) => {
if (!action.meta || !action.meta.delay) {
return next(action)
}
const timeoutId = setTimeout(() => next(action), action.meta.delay)
return function cancel() {
clearTimeout(timeoutId)
}
}
/**
* Schedules actions with { meta: { raf: true } } to be dispatched inside a rAF loop
* frame. Makes `dispatch` return a function to remove the action from the queue in
* this case.
*/
const rafScheduler = (store) => (next) => {
const queuedActions = []
let frame = null
function loop() {
frame = null
try {
if (queuedActions.length) {
next(queuedActions.shift())
}
} finally {
maybeRaf()
}
}
function maybeRaf() {
if (queuedActions.length && !frame) {
frame = requestAnimationFrame(loop)
}
}
return (action) => {
if (!action.meta || !action.meta.raf) {
return next(action)
}
queuedActions.push(action)
maybeRaf()
return function cancel() {
queuedActions = queuedActions.filter((a) => a !== action)
}
}
}
/**
* Lets you dispatch promises in addition to actions.
* If the promise is resolved, its result will be dispatched as an action.
* The promise is returned from `dispatch` so the caller may handle rejection.
*/
const vanillaPromise = (store) => (next) => (action) => {
if (typeof action.then !== 'function') {
return next(action)
}
return Promise.resolve(action).then(store.dispatch)
}
/**
* Lets you dispatch special actions with a { promise } field.
*
* This middleware will turn them into a single action at the beginning,
* and a single success (or failure) action when the `promise` resolves.
*
* For convenience, `dispatch` will return the promise so the caller can wait.
*/
const readyStatePromise = (store) => (next) => (action) => {
if (!action.promise) {
return next(action)
}
function makeAction(ready, data) {
const newAction = Object.assign({}, action, { ready }, data)
delete newAction.promise
return newAction
}
next(makeAction(false))
return action.promise.then(
(result) => next(makeAction(true, { result })),
(error) => next(makeAction(true, { error }))
)
}
/**
* Lets you dispatch a function instead of an action.
* This function will receive `dispatch` and `getState` as arguments.
*
* Useful for early exits (conditions over `getState()`), as well
* as for async control flow (it can `dispatch()` something else).
*
* `dispatch` will return the return value of the dispatched function.
*/
const thunk = (store) => (next) => (action) =>
typeof action === 'function'
? action(store.dispatch, store.getState)
: next(action)
// You can use all of them! (It doesn't mean you should.)
const todoApp = combineReducers(reducers)
const store = createStore(
todoApp,
applyMiddleware(
rafScheduler,
timeoutScheduler,
thunk,
vanillaPromise,
readyStatePromise,
logger,
crashReporter
)
)
```
redux-4.2.1/docs/advanced/NextSteps.md 0000664 0000000 0000000 00000013475 14365314725 0017645 0 ustar 00root root 0000000 0000000 ---
id: next-steps
title: Next Steps
sidebar_label: Next Steps
hide_title: true
---
# Next Steps
If you landed in this section, you might be wondering at this point, "what should I do now?". Here is where we provide some essential tips/suggestions on how to diverge from creating trivial TodoMVC apps to a real world application.
## Tips & Considerations For The Real World
Whenever we decide to create a new project, we tend to bypass several aspects that in the future may slow us down. In a real world project we have to consider several things before we start coding, such as: how to configure a `store`, `store` size, data structure, state model, middlewares, environment, async transactions, immutability, etc..
The above are some of the main considerations we have to think about beforehand. It's not an easy task, but there are some strategies for making it go smoothly.
### UI vs State
One of the biggest challenges developers face when using Redux is to _describe UI state with data_. The majority of software programs out there are just data transformation, and having the clear understanding that UIs are simply data beautifully presented facilitates the process of building them.
_Nicolas Hery_ describes it really well in _"[Describing UI state with data](http://nicolashery.com/describing-ui-state-with-data/)"_. Also, it's always good to know _[When to use Redux](https://medium.com/@fastphrase/when-to-use-redux-f0aa70b5b1e2)_, because a lot of times _[You Might Not Need Redux](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367)_
### Configure a Store
To configure a `store` we have to make major considerations on which middleware to use. There are several libraries out there, but the most popular ones are:
#### Perform Asynchronous dispatch
- [redux-thunk](https://github.com/gaearon/redux-thunk)
- Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. It incorporates the methods `dispatch` and `getState` as parameters.
- [redux-saga](https://github.com/redux-saga/redux-saga)
- redux-saga is a library that aims to make the execution of application side effects (e.g., asynchronous tasks like data fetching and impure procedures such as accessing the browser cache) manageable and efficient. It's simple to test, as it uses the ES6 feature called `generators`, making the flow as easy to read as synchronous code.
- [redux-observable](https://github.com/redux-observable/redux-observable)
- redux-observable is a middleware for redux that is inspired by redux-thunk. It allows developers to dispatch a function that returns an `Observable`, `Promise` or `iterable` of action(s). When the observable emits an action, or the promise resolves an action, or the iterable gives an action out, that action is then dispatched as usual.
#### Development Purposes / debug
- [redux-devtools](https://github.com/reduxjs/redux-devtools)
- Redux DevTools is a set of tools for your Redux development workflow.
- [redux-logger](https://github.com/evgenyrodionov/redux-logger)
- redux-logger logs all actions that are being dispatched to the store.
To be able to choose one of these libraries we must take into account whether we are building a small or large application. Usability, code standards, and JavaScript knowledge may also be considered. All of them are similar.
**Tip**: Think of middlewares as **skills** you give to your `store`. i.e: By attributing the `redux-thunk` to your store, you're giving the `store` the ability to dispatch async actions.
### Naming Convention
A big source of confusion when it comes to a large project is what to name things. This is often just as important as the code itself. Defining a naming convention for your actions at the very beginning of a project and sticking to that convention helps you to scale up as the scope of the project grows.
Great source:
[A Simple Naming Convention for Action Creators in Redux](https://decembersoft.com/posts/a-simple-naming-convention-for-action-creators-in-redux-js/)
and
[Redux Patterns and Anti-Patterns](https://tech.affirm.com/redux-patterns-and-anti-patterns-7d80ef3d53bc)
**Tip**: Set up an opinionated code formatter, such as [Prettier](https://github.com/prettier/prettier).
### Scalability
There is no magic to analyze and predict how much your application is going to grow. But it's okay! Redux's simplistic foundation means it will adapt to many kinds of applications as they grow. Here are some resources on how to build up your application in a sensible manner:
- [Taming Large React Applications with Redux](http://slides.com/joelkanzelmeyer/taming-large-redux-apps#/)
- [Real-World React and Redux - part l](https://dzone.com/articles/real-world-reactjs-and-redux-part-1)
- [Real-World React and Redux - part ll](https://dzone.com/articles/real-world-reactjs-and-redux-part-2)
- [Redux: Architecting and scaling a new web app at the NY Times](https://www.youtube.com/watch?v=lI3IcjFg9Wk)
**Tip**: It's great to plan things beforehand, but don't get caught up in ["analysis paralysis"](https://en.wikipedia.org/wiki/Analysis_paralysis). Done is always better than perfect, after all. And [Redux makes refactoring easy](https://blog.boldlisting.com/so-youve-screwed-up-your-redux-store-or-why-redux-makes-refactoring-easy-400e19606c71) if you need to.
With all that being said, the best practice is to keep coding and learning. Participate in [issues](https://github.com/reduxjs/redux/issues) and [StackOverFlow questions](https://stackoverflow.com/questions/tagged/redux). Helping others is a great way of mastering Redux.
**Tip**: A repository with an extensive amount of content about best practices and Redux architecture is shared by @markerikson at [react-redux-links](https://github.com/markerikson/react-redux-links).
redux-4.2.1/docs/advanced/README.md 0000664 0000000 0000000 00000001035 14365314725 0016632 0 ustar 00root root 0000000 0000000 ---
id: advanced-tutorial
title: Advanced Tutorial: Intro
sidebar_label: Advanced Tutorial: Intro
hide_title: true
---
# Advanced
In the [basics walkthrough](../basics/README.md), we explored how to structure a simple Redux application. In this walkthrough, we will explore how AJAX and routing fit into the picture.
- [Async Actions](AsyncActions.md)
- [Async Flow](AsyncFlow.md)
- [Middleware](Middleware.md)
- [Usage with React Router](UsageWithReactRouter.md)
- [Example: Reddit API](ExampleRedditAPI.md)
- [Next Steps](NextSteps.md)
redux-4.2.1/docs/advanced/UsageWithReactRouter.md 0000664 0000000 0000000 00000020074 14365314725 0021761 0 ustar 00root root 0000000 0000000 ---
id: usage-with-react-router
title: Usage with React Router
sidebar_label: Usage with React Router
hide_title: true
---
# Usage with React Router
So you want to do routing with your Redux app. You can use it with [React Router](https://github.com/ReactTraining/react-router). Redux will be the source of truth for your data and React Router will be the source of truth for your URL. In most of the cases, **it is fine** to have them separate unless you need to time travel and rewind actions that trigger a URL change.
## Installing React Router
`react-router-dom` is available on npm . This guides assumes you are using `react-router-dom@^4.1.1`.
`npm install --save react-router-dom`
## Configuring the Fallback URL
Before integrating React Router, we need to configure our development server. Indeed, our development server may be unaware of the declared routes in React Router configuration. For example, if you access `/todos` and refresh, your development server needs to be instructed to serve `index.html` because it is a single-page app. Here's how to enable this with popular development servers.
> ### Note on Create React App
>
> If you are using Create React App, you won't need to configure a fallback URL, it is automatically done.
### Configuring Express
If you are serving your `index.html` from Express:
```js
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'))
})
```
### Configuring WebpackDevServer
If you are serving your `index.html` from WebpackDevServer:
You can add to your webpack.config.dev.js:
```js
devServer: {
historyApiFallback: true
}
```
## Connecting React Router with Redux App
Along this chapter, we will be using the [Todos](https://github.com/reduxjs/redux/tree/master/examples/todos) example. We recommend you to clone it while reading this chapter.
First we will need to import `
Show:
{this.props.sandwiches.join('mustard')}
} } export default connect((state) => ({ sandwiches: state.sandwiches, }))(SandwichShop) ``` #### Tips - Middleware only wraps the store's [`dispatch`](Store.md#dispatchaction) function. Technically, anything a middleware can do, you can do manually by wrapping every `dispatch` call, but it's easier to manage this in a single place and define action transformations on the scale of the whole project. - If you use other store enhancers in addition to `applyMiddleware`, make sure to put `applyMiddleware` before them in the composition chain because the middleware is potentially asynchronous. For example, it should go before [redux-devtools](https://github.com/reduxjs/redux-devtools) because otherwise the DevTools won't see the raw actions emitted by the Promise middleware and such. - If you want to conditionally apply a middleware, make sure to only import it when it's needed: ```js let middleware = [a, b] if (process.env.NODE_ENV !== 'production') { const c = require('some-debug-middleware') const d = require('another-debug-middleware') middleware = [...middleware, c, d] } const store = createStore( reducer, preloadedState, applyMiddleware(...middleware) ) ``` This makes it easier for bundling tools to cut out unneeded modules and reduces the size of your builds. - Ever wondered what `applyMiddleware` itself is? It ought to be an extension mechanism more powerful than the middleware itself. Indeed, `applyMiddleware` is an example of the most powerful Redux extension mechanism called [store enhancers](../Glossary.md#store-enhancer). It is highly unlikely you'll ever want to write a store enhancer yourself. Another example of a store enhancer is [redux-devtools](https://github.com/reduxjs/redux-devtools). Middleware is less powerful than a store enhancer, but it is easier to write. - Middleware sounds much more complicated than it really is. The only way to really understand middleware is to see how the existing middleware works, and try to write your own. The function nesting can be intimidating, but most of the middleware you'll find are, in fact, 10-liners, and the nesting and composability is what makes the middleware system powerful. - To apply multiple store enhancers, you may use [`compose()`](./compose.md). redux-4.2.1/docs/api/bindActionCreators.md 0000664 0000000 0000000 00000010305 14365314725 0020456 0 ustar 00root root 0000000 0000000 --- id: bindactioncreators title: bindActionCreators sidebar_label: bindActionCreators hide_title: true --- # `bindActionCreators(actionCreators, dispatch)` Turns an object whose values are [action creators](../Glossary.md#action-creator), into an object with the same keys, but with every action creator wrapped into a [`dispatch`](Store.md#dispatchaction) call so they may be invoked directly. Normally you should just call [`dispatch`](Store.md#dispatchaction) directly on your [`Store`](Store.md) instance. If you use Redux with React, [react-redux](https://github.com/gaearon/react-redux) will provide you with the [`dispatch`](Store.md#dispatchaction) function so you can call it directly, too. The only use case for `bindActionCreators` is when you want to pass some action creators down to a component that isn't aware of Redux, and you don't want to pass [`dispatch`](Store.md#dispatchaction) or the Redux store to it. For convenience, you can also pass an action creator as the first argument, and get a dispatch wrapped function in return. #### Parameters 1. `actionCreators` (_Function_ or _Object_): An [action creator](../Glossary.md#action-creator), or an object whose values are action creators. 2. `dispatch` (_Function_): A [`dispatch`](Store.md#dispatchaction) function available on the [`Store`](Store.md) instance. #### Returns (_Function_ or _Object_): An object mimicking the original object, but with each function immediately dispatching the action returned by the corresponding action creator. If you passed a function as `actionCreators`, the return value will also be a single function. #### Example #### `TodoActionCreators.js` ```js export function addTodo(text) { return { type: 'ADD_TODO', text, } } export function removeTodo(id) { return { type: 'REMOVE_TODO', id, } } ``` #### `SomeComponent.js` ```js import { Component } from 'react' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import * as TodoActionCreators from './TodoActionCreators' console.log(TodoActionCreators) // { // addTodo: Function, // removeTodo: Function // } class TodoListContainer extends Component { constructor(props) { super(props) const { dispatch } = props // Here's a good use case for bindActionCreators: // You want a child component to be completely unaware of Redux. // We create bound versions of these functions now so we can // pass them down to our child later. this.boundActionCreators = bindActionCreators(TodoActionCreators, dispatch) console.log(this.boundActionCreators) // { // addTodo: Function, // removeTodo: Function // } } componentDidMount() { // Injected by react-redux: let { dispatch } = this.props // Note: this won't work: // TodoActionCreators.addTodo('Use Redux') // You're just calling a function that creates an action. // You must dispatch the action, too! // This will work: let action = TodoActionCreators.addTodo('Use Redux') dispatch(action) } render() { // Injected by react-redux: let { todos } = this.props return