Skip to content

Commit

Permalink
Nuke most "ES2015" references
Browse files Browse the repository at this point in the history
  • Loading branch information
markerikson committed Nov 25, 2023
1 parent ddf44fe commit 5dcefbe
Show file tree
Hide file tree
Showing 18 changed files with 88 additions and 81 deletions.
2 changes: 1 addition & 1 deletion docs/api/combineReducers.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Any reducer passed to `combineReducers` must satisfy these rules:

- It must never return `undefined`. It is too easy to do this by mistake via an early `return` statement, so `combineReducers` throws if you do that instead of letting the error manifest itself somewhere else.

- If the `state` given to it is `undefined`, it must return the initial state for this specific reducer. According to the previous rule, the initial state must not be `undefined` either. It is handy to specify it with ES2015 optional arguments syntax, but you can also explicitly check the first argument for being `undefined`.
- If the `state` given to it is `undefined`, it must return the initial state for this specific reducer. According to the previous rule, the initial state must not be `undefined` either. It is handy to specify it with optional arguments syntax, but you can also explicitly check the first argument for being `undefined`.

While `combineReducers` attempts to check that your reducers conform to some of these rules, you should remember them, and do your best to follow them. `combineReducers` will check your reducers by passing `undefined` to them; this is done even if you specify initial state to `Redux.createStore(combineReducers(...), initialState)`. Therefore, you **must** ensure your reducers work properly when receiving `undefined` as state, even if you never intend for them to actually receive `undefined` in your own code.

Expand Down
2 changes: 1 addition & 1 deletion docs/faq/Actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ There are [many async/side effect middlewares available](https://github.com/mark
As a general rule of thumb:

- Thunks are best for complex synchronous logic (especially code that needs access to the entire Redux store state), and simple async logic (like basic AJAX calls). With the use of `async/await`, it can be reasonable to use thunks for some more complex promise-based logic as well.
- Sagas are best for complex async logic and decoupled "background thread"-type behavior, especially if you need to listen to dispatched actions (which is something that can't be done with thunks). They require familiarity with ES2015 generator functions and `redux-saga`'s "effects" operators.
- Sagas are best for complex async logic and decoupled "background thread"-type behavior, especially if you need to listen to dispatched actions (which is something that can't be done with thunks). They require familiarity with generator functions and `redux-saga`'s "effects" operators.
- Observables solve the same problems as sagas, but rely on RxJS to implement async behavior. They require familiarity with the RxJS API.

We recommend that most Redux users should start with thunks, and then add an additional side effect library like sagas or observables later if their app really requires handling for more complex async logic.
Expand Down
8 changes: 7 additions & 1 deletion docs/faq/General.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,13 @@ Redux can be used as a data store for any UI layer. The most common usage is wit

## Do I need to have a particular build tool to use Redux?

Redux is originally written in ES2015 and transpiled for production into ES5 with Webpack and Babel. You should be able to use it regardless of your JavaScript build process. Redux also offers a UMD build that can be used directly without any build process at all. The [counter-vanilla](https://github.com/reduxjs/redux/tree/master/examples/counter-vanilla) example demonstrates basic ES5 usage with Redux included as a `<script>` tag. As the relevant pull request says:
Redux is written using modern JS syntax (ES2020), but the code is fairly simple.

If you need to target older browsers, please transpile it yourself.

. You should be able to use it regardless of your JavaScript build process. Redux also offers a UMD build that can be used directly without any build process at all.

The [counter-vanilla](https://github.com/reduxjs/redux/tree/master/examples/counter-vanilla) example demonstrates basic ES5 usage with Redux included as a `<script>` tag. As the relevant pull request says:

> The new Counter Vanilla example is aimed to dispel the myth that Redux requires Webpack, React, hot reloading, sagas, action creators, constants, Babel, npm, CSS modules, decorators, fluent Latin, an Egghead subscription, a PhD, or an Exceeds Expectations O.W.L. level.
>
Expand Down
4 changes: 2 additions & 2 deletions docs/faq/ImmutableData.md
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ JavaScript was never designed to provide guaranteed immutable operations. Accord

With JavaScript, you can accidentally mutate an object (such as the Redux state tree) quite easily without realizing it. For example, updating deeply nested properties, creating a new _reference_ to an object instead of a new object, or performing a shallow copy rather than a deep copy, can all lead to inadvertent object mutations, and can trip up even the most experienced JavaScript coder.

To avoid these issues, ensure you follow the recommended [immutable update patterns for ES2015](../usage/structuring-reducers/ImmutableUpdatePatterns.md).
To avoid these issues, ensure you follow the recommended [immutable update patterns](../usage/structuring-reducers/ImmutableUpdatePatterns.md).

### Verbose Code

Expand All @@ -470,7 +470,7 @@ In contrast, immutable libraries such as Immer can employ structural sharing, wh

**Documentation**

- [Immutable Update Patterns for ES2015](../usage/structuring-reducers/ImmutableUpdatePatterns.md)
- [Immutable Update Patterns](../usage/structuring-reducers/ImmutableUpdatePatterns.md)

**Articles**

Expand Down
116 changes: 59 additions & 57 deletions docs/introduction/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ It helps you write applications that behave consistently, run in different envir

You can use Redux together with [React](https://reactjs.org), or with any other view library. It is tiny (2kB, including dependencies), but has a large ecosystem of addons available.

## Installation

### Redux Toolkit

[**Redux Toolkit**](https://redux-toolkit.js.org) is our official standard approach for writing Redux logic. It wraps around the Redux core, and contains packages and functions that we think are essential for building a Redux app. Redux Toolkit builds in our suggested best practices, simplifies most Redux tasks, prevents common mistakes, and makes it easier to write Redux applications.
[**Redux Toolkit**](https://redux-toolkit.js.org) is our official recommended approach for writing Redux logic. It wraps around the Redux core, and contains packages and functions that we think are essential for building a Redux app. Redux Toolkit builds in our suggested best practices, simplifies most Redux tasks, prevents common mistakes, and makes it easier to write Redux applications.

RTK includes utilities that help simplify many common use cases, including [store setup](https://redux-toolkit.js.org/api/configureStore),
[creating reducers and writing immutable update logic](https://redux-toolkit.js.org/api/createreducer),
Expand All @@ -27,6 +23,10 @@ Whether you're a brand new Redux user setting up your first project, or an exper
simplify an existing application, **[Redux Toolkit](https://redux-toolkit.js.org/)** can help you
make your Redux code better.

## Installation

### Redux Toolkit

Redux Toolkit is available as a package on NPM for use with a module bundler or in a Node application:

```bash
Expand Down Expand Up @@ -79,6 +79,60 @@ The whole global state of your app is stored in an object tree inside a single _
The only way to change the state tree is to create an _action_, an object describing what happened, and _dispatch_ it to the store.
To specify how state gets updated in response to an action, you write pure _reducer_ functions that calculate a new state based on the old state and the action.

Redux Toolkit simplifies the process of writing Redux logic and setting up the store. With Redux Toolkit, the basic app logic looks like:

```js
import { createSlice, configureStore } from '@reduxjs/toolkit'

const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
incremented: state => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes
state.value += 1
},
decremented: state => {
state.value -= 1
}
}
})

export const { incremented, decremented } = counterSlice.actions

const store = configureStore({
reducer: counterSlice.reducer
})

// Can still subscribe to the store
store.subscribe(() => console.log(store.getState()))

// Still pass action objects to `dispatch`, but they're created for us
store.dispatch(incremented())
// {value: 1}
store.dispatch(incremented())
// {value: 2}
store.dispatch(decremented())
// {value: 1}
```

Instead of mutating the state directly, you specify the mutations you want to happen with plain objects called _actions_. Then you write a special function called a _reducer_ to decide how every action transforms the entire application's state.

In a typical Redux app, there is just a single store with a single root reducing function. As your app grows, you split the root reducer into smaller reducers independently operating on the different parts of the state tree. This is exactly like how there is just one root component in a React app, but it is composed out of many small components.

This architecture might seem like a lot for a counter app, but the beauty of this pattern is how well it scales to large and complex apps. It also enables very powerful developer tools, because it is possible to trace every mutation to the action that caused it. You can record user sessions and reproduce them just by replaying every action.

Redux Toolkit allows us to write shorter logic that's easier to read, while still following the same Redux behavior and data flow.

### Legacy Example

For comparison, the original Redux legacy syntax (with no abstractions) looks like this:

```js
import { createStore } from 'redux'

Expand Down Expand Up @@ -125,58 +179,6 @@ store.dispatch({ type: 'counter/decremented' })
// {value: 1}
```

Instead of mutating the state directly, you specify the mutations you want to happen with plain objects called _actions_. Then you write a special function called a _reducer_ to decide how every action transforms the entire application's state.

In a typical Redux app, there is just a single store with a single root reducing function. As your app grows, you split the root reducer into smaller reducers independently operating on the different parts of the state tree. This is exactly like how there is just one root component in a React app, but it is composed out of many small components.

This architecture might seem like a lot for a counter app, but the beauty of this pattern is how well it scales to large and complex apps. It also enables very powerful developer tools, because it is possible to trace every mutation to the action that caused it. You can record user sessions and reproduce them just by replaying every action.

### Redux Toolkit Example

Redux Toolkit simplifies the process of writing Redux logic and setting up the store. With Redux Toolkit, that same logic looks like:

```js
import { createSlice, configureStore } from '@reduxjs/toolkit'

const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
incremented: state => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes
state.value += 1
},
decremented: state => {
state.value -= 1
}
}
})

export const { incremented, decremented } = counterSlice.actions

const store = configureStore({
reducer: counterSlice.reducer
})

// Can still subscribe to the store
store.subscribe(() => console.log(store.getState()))

// Still pass action objects to `dispatch`, but they're created for us
store.dispatch(incremented())
// {value: 1}
store.dispatch(incremented())
// {value: 2}
store.dispatch(decremented())
// {value: 1}
```

Redux Toolkit allows us to write shorter logic that's easier to read, while still following the same Redux behavior and data flow.

## Learn Redux

We have a variety of resources available to help you learn Redux.
Expand Down
2 changes: 1 addition & 1 deletion docs/style-guide/style-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ As mentioned in [Reducers Should Own the State Shape](#reducers-should-own-the-s
The key names in the object passed to `combineReducers` will define the names of the keys in the resulting state object. Be sure to name these keys after the data that is kept inside, and avoid use of the word "reducer" in the key names. Your object should look like `{users: {}, posts: {}}`, rather than `{usersReducer: {}, postsReducer: {}}`.

<DetailedExplanation>
ES2015 object literal shorthand makes it easy to define a key name and a value in an object at the same time:
Object literal shorthand makes it easy to define a key name and a value in an object at the same time:

```js
const data = 42
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ When we receive the `fetchPosts.fulfilled` action, we can use the `postsAdapter.

When we receive the `addNewPost.fulfilled` action, we know we need to add that one new post object to our state. We can use the adapter functions as reducers directly, so we'll pass `postsAdapter.addOne` as the reducer function to handle that action.

Finally, we can replace the old hand-written `selectAllPosts` and `selectPostById` selector functions with the ones generated by `postsAdapter.getSelectors`. Since the selectors are called with the root Redux state object, they need to know where to find our posts data in the Redux state, so we pass in a small selector that returns `state.posts`. The generated selector functions are always called `selectAll` and `selectById`, so we can use ES2015 destructuring syntax to rename them as we export them and match the old selector names. We'll also export `selectPostIds` the same way, since we want to read the list of sorted post IDs in our `<PostsList>` component.
Finally, we can replace the old hand-written `selectAllPosts` and `selectPostById` selector functions with the ones generated by `postsAdapter.getSelectors`. Since the selectors are called with the root Redux state object, they need to know where to find our posts data in the Redux state, so we pass in a small selector that returns `state.posts`. The generated selector functions are always called `selectAll` and `selectById`, so we can use destructuring syntax to rename them as we export them and match the old selector names. We'll also export `selectPostIds` the same way, since we want to read the list of sorted post IDs in our `<PostsList>` component.

### Optimizing the Posts List

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ export default function appReducer(state = initialState, action) {
}
```

A reducer may be called with `undefined` as the state value when the application is being initialized. If that happens, we need to provide an initial state value so the rest of the reducer code has something to work with. **Reducers normally use ES2015 default argument syntax to provide initial state: `(state = initialState, action)`**.
A reducer may be called with `undefined` as the state value when the application is being initialized. If that happens, we need to provide an initial state value so the rest of the reducer code has something to work with. **Reducers normally use default argument syntax to provide initial state: `(state = initialState, action)`**.

Next, let's add the logic to handle the `'todos/todoAdded'` action.

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/fundamentals/part-8-modern-redux.md
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ export const selectFilteredTodoIds = createSelector(
)
```

We call `todosAdapter.getSelectors`, and pass in a `state => state.todos` selector that returns this slice of state. From there, the adapter generates a `selectAll` selector that takes the _entire_ Redux state tree, as usual, and loops over `state.todos.entities` and `state.todos.ids` to give us the complete array of todo objects. Since `selectAll` doesn't tell us _what_ we're selecting, we can use ES2015 destructuring syntax to rename the function to `selectTodos`. Similarly, we can rename `selectById` to `selectTodoById`.
We call `todosAdapter.getSelectors`, and pass in a `state => state.todos` selector that returns this slice of state. From there, the adapter generates a `selectAll` selector that takes the _entire_ Redux state tree, as usual, and loops over `state.todos.entities` and `state.todos.ids` to give us the complete array of todo objects. Since `selectAll` doesn't tell us _what_ we're selecting, we can use destructuring syntax to rename the function to `selectTodos`. Similarly, we can rename `selectById` to `selectTodoById`.

Notice that our other selectors still use `selectTodos` as an input. That's because it's still returning an array of todo objects this whole time, no matter whether we were keeping the array as the entire `state.todos`, keeping it as a nested array, or storing it as a normalized object and converting to an array. Even as we've made all these changes to how we stored our data, the use of selectors allowed us to keep the rest of our code the same, and the use of memoized selectors has helped the UI perform better by avoiding unnecessary rerenders.

Expand Down
2 changes: 1 addition & 1 deletion docs/understanding/history-and-design/PriorArt.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,4 @@ Meet some of the outstanding companies that made it possible:
- [Webflow](https://github.com/webflow)
- [Ximedes](https://www.ximedes.com/)

[See the full list of Redux patrons](<[PATRONS.md](https://github.com/reduxjs/redux/blob/master/PATRONS.md)>), as well as the always-growing list of [people and companies that use Redux](https://github.com/reduxjs/redux/issues/310).
[See the full list of original Redux patrons](https://github.com/reduxjs/redux/blob/master/PATRONS.md), as well as the always-growing list of [people and companies that use Redux](https://github.com/reduxjs/redux/issues/310).
2 changes: 1 addition & 1 deletion docs/usage/ServerRendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ npm install express react-redux

The following is the outline for what our server side is going to look like. We are going to set up an [Express middleware](https://expressjs.com/guide/using-middleware.html) using [app.use](http://expressjs.com/api.html#app.use) to handle all requests that come in to our server. If you're unfamiliar with Express or middleware, just know that our handleRender function will be called every time the server receives a request.

Additionally, as we are using ES2015 and JSX syntax, we will need to compile with [Babel](https://babeljs.io/) (see [this example of a Node Server with Babel](https://github.com/babel/example-node-server)) and the [React preset](https://babeljs.io/docs/plugins/preset-react/).
Additionally, as we are using modern JS and JSX syntax, we will need to compile with [Babel](https://babeljs.io/) (see [this example of a Node Server with Babel](https://github.com/babel/example-node-server)) and the [React preset](https://babeljs.io/docs/plugins/preset-react/).

##### `server.js`

Expand Down
2 changes: 1 addition & 1 deletion docs/usage/side-effects-approaches.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ We've intentionally designed the RTK listener middleware to be straightforward t

We specifically recommend _against_ sagas or observables for most reactive logic for multiple reasons:

- Sagas: require understanding ES2015 generator function syntax as well as the saga effects behaviors; add multiple levels of indirection due to needing extra actions dispatched; have poor TypeScript support; and the power and complexity is simply not needed for most Redux use cases.
- Sagas: require understanding generator function syntax as well as the saga effects behaviors; add multiple levels of indirection due to needing extra actions dispatched; have poor TypeScript support; and the power and complexity is simply not needed for most Redux use cases.
- Observables: require understanding the RxJS API and mental model; can be difficult to debug; can add significant bundle size

## Common Side Effects Approaches
Expand Down
Loading

0 comments on commit 5dcefbe

Please sign in to comment.