preface

This article zero basis can also read, I try to write simple and easy to understand, if you feel a little difficult to understand, you can also go to the official website for entry.

This article also includes a lot of actual combat code, but due to the length of the article, I did not directly show some actual combat examples, but put them in the sandBox link, in addition to the slow advantages of many.

1. Why is Redux created?

Why is it there in the first place

1. Trend: With the increasing complexity of JavaScript single page application development, JavaScript needs to manage more states than ever before.

2. Managing changing states is very difficult: if a change in one model causes a change in another model, then when the view changes, it may cause changes in the corresponding model as well as in another model, which in turn may cause changes in another view. When, for what reason, and how state changes are out of control.

What does Redux do?

At the end of the day, it’s just a tool, and to understand a tool is to understand what it does in the first place.

Redux is a JavaScript state container that provides predictable state management.

Be more specific:

  • Redux stores the entire application state (i.e., data) toStore
  • Store stores a state tree (state tree)
  • The only way a component can change state is by calling storedispatchMethod to trigger aaction, this action is corresponding toreducerState completes the update
  • Components can dispatch actions to stores instead of notifying other components directly
  • Other components can refresh their views by subscribing to states in the Store

You can see it in combination with this picture:

How to use Redux?

Official Website Example (ToDO)

State: Uses a common object to describe State in the application, without setters (modifier methods)

{
  todos: [{
    text: 'Eat food'.completed: true
  }, {
    text: 'Exercise'.completed: false}].visibilityFilter: 'SHOW_COMPLETED'
}
Copy the code

Action: To update the data in state, such as adding todo, initiate an Action. An Action is just a normal JavaScript object, an indicator of what’s going on, okay

{ type: 'ADD_TODO'.text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO'.index: 1 }
{ type: 'SET_VISIBILITY_FILTER'.filter: 'SHOW_ALL' }
Copy the code

The advantage of forcing action to describe all changes is that it is clear what is happening in the application. If something changes, you can see why.

Reducer: String actions and states together. Reducer is just a function that receives state and action and returns a new state.

// Write many small functions to manage parts of state separately
function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter;
  } else {
    returnstate; }}function todos(state = [], action) {
  switch (action.type) {
  case 'ADD_TODO':
    return state.concat([{ text: action.text, completed: false }]);
  case 'TOGGLE_TODO':
    return state.map((todo, index) = >
      action.index === index ?
        { text: todo.text, completed: !todo.completed } :
        todo
   )
  default:
    returnstate; }}Copy the code
Call the two reducers to manage the state of the entire application
function todoApp(state = {}, action) {
  return {
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  };
}
Copy the code

Handwriting Combat (TodoList)

And if you’re interested, take a look at the Codesandbox-Todolist example which might be a little slow.

If you haven’t used the Sandbox, let me show you something like this:I think this is more intuitive, so some of the links in the back are still posted ~ Todo this example is relatively simple, equivalent to the introduction, understanding Redux work.

Fourth, the react – story

Notice that we didn’t use react-Redux above. Although the function can be implemented, if you are careful, you will find that I directly take stores. If there are many components, each store is taken. Let me summarize some of the headaches that can occur without react-Redux. For example:

1. The Store is not obvious, and as the component hierarchy becomes more complex, the store becomes difficult to control.

2. The logical components look very messy. The reason for the confusion is that state and dispatch are not written together.

3. The React component reads data from the Redux store and distributes actions to the store to update data.

Provider

The Provider is used to inject the store into the context, and the connect is used to convert the context to props. All components can be controlled by React-Redux, and all components can access data in redux.

<Provider store={store}>
    <App />
 </Provider>,
Copy the code

connect

  • Technically, a container component reads some data from the Redux state tree using store.subscribe() and feeds that data to the component to be rendered via props.
  • Why use it? Simply put, it will save work if you don’t have to manually develop container components and implement shouldComponentUpdate for performance.
  • Use the Connect () method of the React Redux library, which is optimized for performance to avoid many unnecessary repeated renderings.

The use of the connect

The code is as follows:

const App = connect(mapStateToProps, mapDispatchToProps)(Counter);
export default App;
Copy the code

mapStateToProps

MapStateToProps mapStateToProps. State is the state of redux, and props is the way of react.

Code:

// Map Redux state to component props
function mapStateToProps(state) {
  return {
    value: state.count
  }
}
Copy the code

Then use this.props. Value in the component to complete the rendering

class Counter extends Component {
  render() {
    const { value, onIncreaseClick } = this.props;
    return (
      <div>
        <span>{value}</span>
        <button onClick={onIncreaseClick}>Increase</button>
      </div>); }}export default Counter;
Copy the code

mapDispatchToProps

Understand the word “mapDispatchToProps”.

// Map Redux actions to component props
 function mapDispatchToProps(dispatch) {
   return {
     onIncreaseClick: () = > dispatch(increaseAction)
   }
 }
Copy the code
class Counter extends Component {
  render() {
    const { value, onIncreaseClick } = this.props;
    return (
      <div>
        <span>{value}</span>
        <button onClick={onIncreaseClick}>Increase</button>
      </div>); }}export default Counter;
Copy the code

Similarly is also can use this. Props. OnIncreaseClick call dispatch, so there is no need for running dispatch in the code.

Connect and Provider application instances

Connect: connect: connect: connect: connect: connect: Connect: Connect

Simply click to add an instance of count. There’s a lot to be optimized for, but learn about connect and Provider.

React-redux: react-redux: hooks; todolist: react-redux: hooks; react-redux: hooks; As long as you concentrate)

Redux: Hooks

If the project is developed using hooks, that’s fine, you save a lot of effort, such as a simple state management example such as a counter, which can be fixed in a few lines of code.

import { useState } from 'react';
function Example() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={()= > setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Copy the code

But can we dispense with redux state management altogether? Hahaha how is that possible

  • For those who already use Redux: First, most projects will not be completely refactoring for hooks until redux provides better support for hooks, and by the way, the problems refactoring can cause:
    • Losing much of the automatic reference caching that Connect () provides can cause performance problems, unless it is wrapped in a lot of useCallback()
    • If your code relies on ownProps in mapStateToProps, you might write more code using redux hooks instead of getting this property directly.
    • Dependency injection for Action Creator cannot be provided in mapDispatchToProps as before
  • For potentially complex applications: Many companies use Redux for state management in large part of their projects, and its many advantages such as single data source, data sharing, transaction state, data state I/O and side effect isolation, state backtracking, and powerful debugging capabilities from a range of ancillary tools make redux a better choice for managing data flows.
  • React-redux has released a new version that is separate from the previous contextAPI and provides support for hooks, which is even better

The new Redux brings changes

  1. No longer needed mapStateToProps.mapDispatchToPropsandconnectTo maintain separate Container components and UI components, instead using the hooks provided by Redux directly in the component to read state in Redux.
  2. You can integrate any existing custom hooks with Redux, rather than passing the state created by hooks as a parameter to other hooks.

Redux support for hooks

First, I will introduce a few core elements:

  • UseSelector: Used to extract values from and subscribe to the state stored by Redux.
  • UseDispatch: In addition to reading state in store, you can dispatch actions to update state in store.
  • UseStore: Used to get the created store instance.

Just look at the introduction is not very clear, one by one:

useSelector

It looks like mapStateToProps, but

  • The ownProps API is not provided. It is best obtained using useCallback or useMemo
  • As with useEffect, every component update is recalculated if a second parameter is not provided

There might be a little bit of concern, is it going to be less useful than the mapStateToProps I used before? Let’s take a look at some of his benefits:

  • Of course it would be simpler to write code with hooks
  • If the current props is the same as the old props, the component will not be re-rendered.
  • Batch updates allow multiple useselectors () to recalculate state, and components will only be re-rendered once, without worrying about useSelector re-rendering.

First look at how it used to be written:

//before

// React component
class Counter extends Component {
  render() {
    const { value, onIncreaseClick } = this.props;
    return (
      <div>
        <span>{value}</span>
        <button onClick={onIncreaseClick}>Increase</button>
      </div>); }}export default Counter;

// Connected Component
// Map Redux state to component props
function mapStateToProps(state) {return {value: state.count}}
// Map Redux actions to component props
function mapDispatchToProps(dispatch) {return {onIncreaseClick: () = > dispatch(increaseAction)}}

// Connected Component
const App = connect(mapStateToProps,mapDispatchToProps)(Counter)
export default App
Copy the code

Then let’s rewrite the previously written counter with the new useSelect:

//after
const Counter = props= > {
  const { count } = useSelector(
    (state) = > ({
      count: state.count
    })
  );
  return (
    <div>
      <span>{count}</span>
    </div>
  );
}
export default Counter;
Copy the code

useDispatch

Before using mapDispatchToProps:

//before
// Map Redux actions to component props
  function mapDispatchToProps(dispatch) {
    return {
      onIncreaseClick: () = > dispatch(increaseAction)
    }
  }
Copy the code

Now use useDispatch, which can be used directly within components, in the form of anonymous functions:

//after
const dispatch = useDispatch();
return (
    <div>
      <button onClick={()= >dispatch(increaseAction)}>Increase</button>
    </div>
  );
Copy the code

Due to the nature of anonymous functions, a new reference is obtained each time it is re-rendered, and if passed as props to the child component, the child component is re-rendered each time.

The best idea is to create this anonymous function in useCallback:

//after
import React, { useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import increaseAction from "./store/action";
const Counter = props= > {
  const { count } = useSelector(
    (state) = > ({
      count: state.count
    })
  );
  const dispatch = useDispatch();
  const onIncreaseClick = useCallback(
    () = > dispatch(increaseAction),[dispatch]
  );
  return (
    <div>
      <span>{count}</span>
      <button onClick={onIncreaseClick}>Increase</button>
    </div>
  );
}
export default Counter;
Copy the code

useStore

In any application that needs to access the Store, it can be accessed through usestore. If for some reason, such as unit testing, we want to get a different store, we can pass the store into the component tree via the new contextAPI, as follows:

import React from 'react';
import { useStore } from 'react-redux';
import OtherProvider from './OtherProvider';

const Component = props= > {
  const store = useStore();
  return <OtherProvider store={store}>{props.children}</OtherProvider>
}
Copy the code

In actual combat

React-redux useSelector and useDispatch are implemented using react-redux useSelector and useDispatch.

The basic idea is pretty much the same as the one I introduced earlier, but here I’m not going to break down the code and use the Sandbox for more intuition though not very quickly:

SandBox —— useSelector, useDispatch Combat TodoList

Redux summary under Hooks

Why redux? To put it simply: Redux provides code organization and debugging capabilities for large applications, helping you quickly locate problems when your application goes wrong.

There are some scenarios where hooks cannot fix requirements:

  • The state needs to be saved or loaded
  • State is shared across components
  • Business logic or data processing needs to be shared with other components

The new Redux makes a difference: it’s also a good attempt to write with hooks using useSelector, useDispatch, and useStore.

conclusion

As a newbie who switched from VUE technology stack to React technology stack, I still made some mistakes. For example, after I got the foundation of VUex, I could easily feel that Redux is similar to redux without a clear understanding of it. However, there are still many differences in reality, which is also a trigger for me to further study Redux.

To recap: In Vuex, $Store is injected directly into the component instance, so it can be used flexibly:

  • Commit updates using Dispatch and COMMIT

  • Read data from mapState or directly from this.$store

  • You can dispatch actions or commit updates in a component

In the story:

  • We need to display each component using connect to connect the props and dispatch needed.
  • Only dispatch can be performed in Redux, and reducer cannot be directly called for modification.

In terms of implementation principles, the biggest differences are two:

Redux uses immutable data, whereas Vuex’s data is mutable. Redux replaces the old state with the new state each time, whereas Vuex is a direct modification.

Redux uses diff to compare data changes, whereas Vuex uses getter/setter to compare data changes, like Vue.

Dig a hole

🚀🚀 this article will probably be updated later, and some have not been written. I hope this article will be helpful for you to learn about Redux

⭐️⭐️ If you feel good, click a like and leave