The difference between

Redux and React-Redux are not the same thing.

Redux is an architectural pattern (a variation of the Flux architecture) that doesn’t care what library you’re using. You can apply it to React and Vue, or even jQuery.

React-redux is a library that combines redux architecture with react. js, which is the embodiment of redux architecture in React.js.

Why use Redux to manage data

Modules (components) need to share data, but everyone can modify it. A data state that can be arbitrarily modified and shared by different modules is evil. Once the data can be arbitrarily modified, all operations on the shared state are unpredictable, and the data can be arbitrarily modified to lead to unexpected results.

First, redux

dispatch

We define a function called Dispatch that is responsible for data modification:

function dispatch (action) {
  switch (action.type) {
    case 'UPDATE_TITLE_TEXT':
      appState.title.text = action.text
      break
    case 'UPDATE_TITLE_COLOR':
      appState.title.color = action.color
      break
    default:
      break}}Copy the code

All operations on the data must go through the Dispatch function. It takes an action, which is a normal JavaScript object that must contain a Type field to declare what you want to do.

store

const store = createStore(appState, Subscribe (() => renderApp(store.getState())) renderApp(store.getState()) store.dispatch({type: 'UPDATE_TITLE_TEXT', text: 'React.js Little Book'}) // Modify the header text store.dispatch({type: 'UPDATE_TITLE_COLOR', color: 'blue'}) // Change the title colorCopy the code

We get the share status with Store.getState, and we agree that we can only change the share status with store.dispatch. Store also allows us to listen to data through store. Subscribe when the data state is modified and perform subsequent operations such as rerendering the page.

reducer

CreateStore accepts as a parameter a reducer function, which is defined as a pure function that accepts two parameters, state and action.

Negative effects are not allowed on reducer. You can’t manipulate the DOM in it, you can’t make Ajax requests, and you can’t modify state directly. All it has to do is take care of the initial state and calculate new states with shared structures based on state and action.

In general, the structure of Redux looks like this

const reducer = (state = {count: 0}, action) => {
  switch (action.type){
    case 'INCREASE': return {count: state.count + 1};
    case 'DECREASE': return {count: state.count - 1};
    default: return state;
  }
}

const actions = {
  increase: () => ({type: 'INCREASE'}),
  decrease: () => ({type: 'DECREASE'})
}

const store = createStore(reducer);

store.subscribe(() =>
  console.log(store.getState())
);

store.dispatch(actions.increase()) // {count: 1}
store.dispatch(actions.increase()) // {count: 2}
store.dispatch(actions.increase()) // {count: 3}
Copy the code

Create a store by reducer. Whenever we dispatch an action on the store, the data in the store will change accordingly.

When creating a store, create a reducer first, and pass the reducer into the index.js Reducer of the store

A Reducer can receive state, but must not modify state

1. Store must be unique

2. Only Store can change its content, but reducer cannot

Reducer must be a pure function (given a fixed input, there must be a given output, return value is certain), that is, no asynchronous operation, no time timer or other operations

API

Store. dispatch: Dispatches actions to help the store

Store. getState: Gets the data in the store

Store. Subscribe: Listens for changes in data, triggering a listening callback

And then there’s React-Redux

First wrap everything around the Provider component in the outermost container, passing the previously created Store as a prop to the Provider.

const App = () => {
  return (
    <Provider store={store}>
      <Comp/>
    </Provider>
  )
};
Copy the code

Any component within a Provider (such as Comp here) that needs to use data from State must be “connected” — the product of wrapping “your component (MyComp)” with connect.

class MyComp extends Component { // content... } const Comp = connect(... args)(MyComp);Copy the code

As you can see, the CONNECT method is the most important.

Connect,

Connect () takes four parameters, mapStateToProps, mapDispatchToProps, mergeProps, and options.

mapStateToProps(state, ownProps) : stateProps

This function allows us to bind the data in the store to the component as props.

const mapStateToProps = (state) => {
  return {
    count: state.count
  }
}
Copy the code

The first argument to this function is Redux’s store, from which we extract the count attribute. Because an object with the count attribute is returned, MyComp will have a props field named count.

class MyComp extends Component {
  render() {return<div> count: {this.props. Count} times </div>}} const Comp = connect(... args)(MyComp);Copy the code

Of course, you don’t have to pass the data in state into the component verbatim; you can dynamically output the (minimal) properties the component needs based on the data in state.

const mapStateToProps = (state) => {
  return {
    greaterThanFive: state.count > 5
  }
}

Copy the code

The second argument to the function, ownProps, is MyComp’s ownProps. Sometimes, ownProps can also influence it. For example, when you maintain a list of users in the Store, your component MyComp only cares about one user (represented by the userId in props).

Const mapStateToProps = (state, ownProps) => {// state is {userList: [{id: 0, name:'the king 2'}}]return {
    user: _.find(state.userList, {id: ownProps.userId})
  }
}

class MyComp extends Component {
  
  static PropTypes = {
    userId: PropTypes.string.isRequired,
    user: PropTypes.object
  };
  
  render() {return<div> user name: {this.props. Username}</div>}} const Comp = connect(mapStateToProps)(MyComp);Copy the code

When state changes, or ownProps changes, mapStateToProps is called, and a new stateProps is computed, which (after merging with ownProps) is updated to MyComp.

This is the basic way to connect data in the Redux Store to components.

mapDispatchToProps(dispatch, ownProps): dispatchProps

The second parameter to connect is mapDispatchToProps, which binds action as props to MyComp.

const mapDispatchToProps = (dispatch, ownProps) => {
  return{ increase: (... args) => dispatch(actions.increase(... args)), decrease: (... args) => dispatch(actions.decrease(... args)) } } class MyComp extends Component {render(){
    const {count, increase, decrease} = this.props;
    return<div> <div> count: {this.props. Count} times </div> <button onClick={increase}> increase </button> <button onClick={decrease}> decrease </button> </div>)}} Const Comp = connect(mapStateToProps, mapDispatchToProps)(MyComp);Copy the code

Since the mapDispatchToProps method returns objects with increase and Decrease properties, these two properties will also be MyComp props.

As shown above, calling actions.increase() yields only one action object {type:’ increase ‘}, which must be triggered by calling the Dispatch method on the store. Diapatch is the first parameter to mapDispatchToProps. However, to keep the MyComp component from sensing dispatch, we need to wrap the increase and Decrease functions so that they are directly callable (that is, calling the method triggers Dispatch).

Redux itself provides the bindActionCreators function, which wraps the action into a straightforward, callable function.

import {bindActionCreators} from 'redux';

const mapDispatchToProps = (dispatch, ownProps) => {
  return bindActionCreators({
    increase: action.increase,
    decrease: action.decrease
  });
}
Copy the code

Also, this function is called when ownProps changes, generating a new dispatchProps, which (after merging with statePrope and ownProps) is updated to MyComp. Note that action changes do not cause the above process, and the default action is fixed for the life of the component.

[mergeProps(stateProps, dispatchProps, ownProps): props]

MyComp = MyComp = MyComp = MyComp = MyComp = MyComp = MyComp = MyComp = MyComp = MyComp = MyComp The third parameter to connect is used to do just that. Normally, you can omit this parameter and connect will use object. assign instead.