Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WRO-9096: Update react-redux related documentation #3081

Merged
merged 26 commits into from
Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 6 additions & 7 deletions docs/redux/redux-async.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,16 @@ import {Component} from 'react';
import {connect} from 'react-redux';
vladut-clapou-lgp marked this conversation as resolved.
Show resolved Hide resolved
import {getSystemSettings} from '../actions';

class App extends Component {
componentDidMount () {
this.props.dispatch(getSystemSettings({
const App = ({dispatch}) => {
useEffect(() => {
dispatch(getSystemSettings({
category: 'picture',
key: 'pictureMode',
subscribe: true
}));
}
render () {
return <p>{this.props.pictureMode}</p>;
}
}, []);

return <p>{this.props.pictureMode}</p>;
}

export default connect()(App);
Expand Down
81 changes: 48 additions & 33 deletions docs/redux/redux-intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This document provides a high-level overview of Redux and how it is used.
### What is Redux?

Redux is a library that allows you to manage application state. It closely follows React's Flux data flow model and works well with React, though it does not require it. State management has become more complicated due to a mixing of mutability and asynchronicity, and redux tries to resolve this issue by make state mutation **predictable**.
State management has become more complicated due to a mixing of mutability and asynchronicity, and redux tries to resolve this issue by make state mutation **predictable**.
vladut-clapou-lgp marked this conversation as resolved.
Show resolved Hide resolved

We recommend using the most recent version of Redux. To see which version of Redux is appropriate, refer to the [Redux Installation Instructions](https://react-redux.js.org/introduction/quick-start#installation).

Expand All @@ -27,6 +28,8 @@ If you want to change the state, you have to **dispatch** an **[action](https://

To describe state mutations you have to write a function that takes the previous state of the app and the action being dispatched, then returns the next state of the app. This function is called the [Reducer](https://redux.js.org/understanding/thinking-in-redux/glossary#reducer).

Please find more information [here](https://redux.js.org/understanding/thinking-in-redux/three-principles).

#### What You Need

* Actions - what your app can do
Expand Down Expand Up @@ -59,6 +62,7 @@ An action is just a POJO (unless you use middleware as described) that contains
}
```


##### Reducers

A reducing function (reducer) returns the next state tree, given the current state tree and an action to handle. Reducers are run in response to actions that are made against the store. Reducing functions should be pure (given the same arguments, they should always return the same value) and perform no side effects (API calls, routing transitions, etc.) or call other non-pure functions (i.e. `Date.now()` or `Math.random()`).
Expand Down Expand Up @@ -99,6 +103,7 @@ const todo = (state, action) => {
}
```


##### Store

The store is where the state tree is stored. It is configured with a reducer. It can also be given an optional initial state tree and optional enhancer functions. We use the enhancer functions to be able to handle async actions through `applyMiddleware` (provided by Redux). The store is created via the [`createStore()`](https://redux.js.org/api/createstore) method of the Redux module. The store allows access to the state via [`getState()`](https://redux.js.org/api/store#getstate) method. It only allows updates to the state by using the [`dispatch()`](https://redux.js.org/api/store#dispatchaction) method (i.e. `dispatch(action)`). It can register listeners via [`subscribe(listener)`](https://redux.js.org/api/store#subscribelistener) and handles unregistering of listeners with the function returned by `subscribe()`.
Expand Down Expand Up @@ -152,8 +157,7 @@ Live demo: [http://jsbin.com/keyahus/edit?html,js,output](http://jsbin.com/keyah
```js
import {createStore} from 'redux';
import PropTypes from 'prop-types';
import {Component} from 'react';
import ReactDOM from 'react-dom';
import { createRoot } from 'react-dom/client';
vladut-clapou-lgp marked this conversation as resolved.
Show resolved Hide resolved
// reducer
function counter (state = 0, action) {
switch (action.type) {
Expand All @@ -163,59 +167,70 @@ function counter (state = 0, action) {
return state;
}
}
vladut-clapou-lgp marked this conversation as resolved.
Show resolved Hide resolved
class Counter extends Component {
render () {
const {value, onIncrement} = this.props;
return (
<p>
Clicked: {value} times
{' '}
<button onClick={onIncrement}>
+
</button>
</p>
);
}
const Counter = ({value, onIncrement}) => {
vladut-clapou-lgp marked this conversation as resolved.
Show resolved Hide resolved
return (
<p>
Clicked: {value} times
{' '}
<button onClick={onIncrement}>
+
</button>
</p>
);
}
Counter.propTypes = {
onIncrement: PropTypes.func.isRequired,
value: PropTypes.number.isRequired
};
const store = createStore(counter);
function render () {
ReactDOM.render(
<Counter
const render = () => {
const appElement = (
<Counter
value={store.getState()}
onIncrement={() => store.dispatch({type: 'INCREMENT'})}
/>,
document.getElementById('root')
);
/>
);
createRoot(document.getElementById('root')).render(appElement);
vladut-clapou-lgp marked this conversation as resolved.
Show resolved Hide resolved
}
render();
store.subscribe(render);
```

Live Demo: [http://jsbin.com/nemofa/edit?html,js,output](http://jsbin.com/nemofa/edit?html,js,output)
Live Demo: [https://jsbin.com/pudurig/edit?html,js,output](https://jsbin.com/pudurig/edit?html,js,output)
vladut-clapou-lgp marked this conversation as resolved.
Show resolved Hide resolved

### Redux and React
### Redux Toolkit

As mentioned above Redux can be used without React. React bindings for redux is available from [react-redux](https://github.com/reduxjs/react-redux), which is a generic library that connects React components to a Redux store. More on how to use it is available [here](https://redux.js.org/tutorials/fundamentals/part-5-ui-react).
The patterns shown above, unfortunately, require lots of verbose and repetitive code. To make it easier to write Redux applications in general, Redux team introduced [Redux Toolkit](https://redux-toolkit.js.org/).
MikyungKim marked this conversation as resolved.
Show resolved Hide resolved
It is the official recommended approach for writing Redux logic as of now.

It includes utilities that help simplify many common use cases, including store setup, creating reducers and writing immutable update logic, and even creating entire "slices" of state at once. It also includes the most widely used Redux addons, like Redux Thunk for async logic and Reselect for writing selector functions, so that you can use them right away.

Redux Toolkit provides two key APIs that simplify the most common things you do in every Redux app.

#### Presentational and Container Components
* [configureStore](https://redux-toolkit.js.org/api/configureStore) sets up a well-configured Redux store with a sing function call, including combining reducers, adding the thunk middleware, and setting up the Redux DevTools integration.

There's a simple and very useful pattern in React apps called **presentational and container components**. The idea is to separate concerns of **_how components should look_** and _**what components should do**_. By following this pattern, you get better separation of concerns, better reusability, and you can handle UI more easily. See [here](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.6j9fz9g5j) to find out more about it. (STRONGLY SUGGESTED!)
* [createSlice](https://redux-toolkit.js.org/api/createSlice) helps you write reducers that use the [Immer](https://immerjs.github.io/immer) library to enable writing immutable updates using "mutating" JS syntax like `state.value = 123`, with no spreads needed. It also automatically generates action creator functions for each reducer, and generates action type strings internally based on your reducer's names.

Redux embraces the separation of presentational and container components idea and it's easy to do with `react-redux`. Essentially, presentational components don't know about Redux. They get their data through standard React props and emit changed data by invoking callbacks passed in through props. Container components are where the hook-up to Redux and app state is done and where Redux actions are dispatched. In other words, you would normally create components as a presentational component, and when you find you need to hook up to data, you would then need to create a container component for it.
Please see [here](https://redux.js.org/introduction/why-rtk-is-redux-today) to find out more about Redux Toolkit.
Also, see [here](https://react-redux.js.org/tutorials/quick-start) for a greate tutorial.

### Redux and React

As mentioned above Redux can be used without React. React bindings for redux is available from [react-redux](https://github.com/reduxjs/react-redux), which is a generic library that connects React components to a Redux store. More on how to use it is available [here](https://redux.js.org/tutorials/fundamentals/part-5-ui-react).

#### What `react-redux` does

`react-redux` allows you to specify how react components get data from the redux store and how they behave by specifying props and the actions to dispatch. We use `react-redux` module's [connect()](https://github.com/reduxjs/react-redux/blob/master/docs/api/connect.md) method to connect the relevant container component to its presentational one.
`react-redux` allows you to specify how react components get data from the redux store and how they behave by calling its own custom hooks. We use `react-redux` module's [useSelector()](https://github.com/reduxjs/react-redux/blob/master/docs/api/hooks.md#useselector) hook to let our React components read data from the Redux store.

An optional `mapStateToProps()` method will map a key of the state tree to the connected presentational component's props (i.e. when you do `connect(mapStateToProps)(PresentationalComponent)`). Container components can also dispatch actions by using the `mapDispatchToProps()` method. It allows you to pass callback props to the presentational component.
Back in the days, we had [connect()](https://github.com/reduxjs/react-redux/blob/master/docs/api/connect.md) and `mapStateToProps()` method to get data from the redux store. They are also available but we recommend using `useSelectors()` hook instead.

Container components need access to the Redux store so they can subscribe to it. This can be cumbersome as your number of components grows and you have to manually pass store around. `react-redux` incorporates [context](https://reactjs.org/docs/context.html) in React and provides a [`<Provider />`](https://github.com/reduxjs/react-redux/blob/master/docs/api/Provider.md) component to make store available to all container components without passings stores around by hand. You only need to use it once at the `render()` of root component.
`useSelector()` accepts a single function, which we call a selector function. A selector is a function that takes the entire Redux store state as its argument, reads some value from the state, and returns that result.

#### Example
Also, we use [useDispatch()](https://github.com/reduxjs/react-redux/blob/master/docs/api/hooks.md#usedispatch) hook to dispatch actions. It gives you the store's `dispatch` method as its result so that you can call it with some `action` to dispatch.

Our components need access to the Redux store so they can subscribe to it. This can be cumbersome as your number of components grows and you have to manually pass store around. `react-redux` incorporates [context](https://reactjs.org/docs/context.html) in React and provides a [`<Provider />`](https://github.com/reduxjs/react-redux/blob/master/docs/api/Provider.md) component to make store available to all components without passings stores around by hand. You only need to use it once at the `render()` of root component.

#### example
vladut-clapou-lgp marked this conversation as resolved.
Show resolved Hide resolved

```js
import {createStore} from 'redux';
vladut-clapou-lgp marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -276,6 +291,6 @@ Live Demo: [http://jsbin.com/zukojok/1/edit?html,js,output](http://jsbin.com/zuk

[Official Redux documentation](http://redux.js.org/)

[Egghead tutorial - Getting Started with Redux](https://egghead.io/courses/getting-started-with-redux)
[Official React Redux documentation](https://react-redux.js.org/tutorials/quick-start)

[Presentational and Container Components](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.6j9fz9g5j)
[Egghead tutorial - Getting Started with Redux](https://egghead.io/courses/getting-started-with-redux)