Redux

  • Redux is a JavaScript state container that provides predictable state management.
  • Allows you to build consistent applications that run in different environments (client, server, native application) and are easy to test.
  • Redux is not an official Facebook product. It doesn’t rely on React and supports other interface libraries besides React.
  • It is small and lean (only 2kB, including dependencies)

Why Redux

  • Redux is a state management library
  • The React component is a state machine, and its view changes as states change, so state management is particularly important
  • In particular, design-to-state can be passed across components. Redux allows us to manage these states more easily, and these states are predictable, and we can do unit testing later on, right
  • It seems to be a tricky thing to say, look at VueX, but in plain English, I want a unified management of data, so I want to use it
  • Important: Centralized storage manages the state of all components of an application and rules to ensure that state changes in a predictable way

The installation

npm i redux

yarn add redux
Copy the code

Redux API

store

  • The React component we useuseStateManaging a single state. Redux also needs something to manage state, which is a store
  • Store – Store/warehouse/container (administrative state)
    • Used to manage the state of Redux applications
    • Redux apps have a single store
    • * * indefaultCase return oldstate. ** When encountering an unknown action, always return to the old onestate

createStore

  • If you want to use a store, you have to create it firstcreateStore
  • createStore(reducer, [preloadedState], enhancer)
    • Reducer (Function) : A pure Function that specifies how changes in application state should respond to actions sent to the store
import { createStore } from 'redux';

const store = createStore(reducer);
Copy the code

reducer

  • Reducer is a pure function
    1. The same input always returns the same output
    2. The input value of the function is not modified
    3. Independent of the state of the external environment
    4. No side effects
    5. To facilitate the test
    6. Good refactoring
  • It provides a variety of ways to provide operational state
  • Basically, what he does is he tells the warehouse, how to read and write data, and how to manipulate it, right
  • Parameters (state, action)
    • State – Used to store state, which represents the entire state of a Redux application, usually as a multi-tiered nested object
    • action– The payload that transfers data from the app to the Store. It’s store dataThe onlySource.
      • Tell store, what do I do to state
      • It is essentially an object
      • Typically, actions are passed to the Store via Dispatch
  • Don’t everDo these in the Reducer:
    • Modify incoming parameters
    • Perform operations that have side effects, such as API requests and route jumps
    • Call an impure function, such asDate.now()Math.random()
function reducer(state = { data: [] }, action) {
  console.log(action);
  return state
}
Copy the code

Store method

  • GetState () – Gets state

  • Dispatch (Action) – Dispatch the action, which is the only way to trigger a state change

    • You must use a string type field within the action to indicate the action to be performed
    • In general, we define type as a constant, so use uppercase. This is not mandatory, just a convention
    • When dispatch is called, the Store calls the reducer function – to receive the oldstateAnd dispatch incomingactionPass reducer. In Reducer, listen for differences in action. Type and return the new state
    • Of course it can support payloads, so if you want to pass in values, you can do it inactionJust write it inside
    • Actions just describesSomething’s upThis fact, it doesn’t describe how the application updates state, right
import { createStore } from 'redux';

function reducer(state = {
  count: 1
}, action) {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        count: state.count + 1
      }
    case 'MINUS':
      return {
        ...state,
        count: state.count - 1
      }
    default:
      return state
  }
}

const store = createStore(reducer);
store.dispatch({
  type: "ADD"
});
console.log(store.getState()); / / 2

store.dispatch({
  type: "MINUS"
});
console.log(store.getState()); / / 1
Copy the code
  • From the results, we can see that Dispatch is a synchronous method

  • Subscribe – Listen for state changes

    • Receives a function that is called when the state changes
    • Returns a function that cancels listening
const unSubscribe = store.subscribe(() = > {
  console.log('State has changed');
});
unSubscribe(); // Cancel the listener
Copy the code
  • replaceReducer(nextReducer)– Replace the reducer currently used by the store to calculate the state
    • This is a high-level API. This should only be used if you need to implement code separation and need to load some reducer immediately
    • It may also be used when implementing the Redux hot loading mechanism

Redux’s Three principles

Single data source

  • Application-widestateIs stored in an object tree and exists in only one object treestore 中
    • This makes homogeneous application development very easy
    • State from the server can be serialized and injected into the client without writing more code
    • Debugging is also very easy because of the single State Tree
    • During development, you can save your application’s state locally to speed up development
    • In addition, features such as undo/redo that were previously difficult to implement become easy thanks to a single State Tree

State is read-only

  • The only way to change state is to triggeractionAction is a generic object that describes events that have occurred
    • This ensures that neither views nor network requests can directly modify state, instead they can only express the intent to change it
    • Because all changes are centralized and executed strictly one after the other, there is no need to worry about race conditions
    • Actions are just ordinary objects, so they can be logged, serialized, stored, and played back during debugging or testing

Use pure functions to perform modifications

  • To describe how an action changes the state tree, you need to writereducers
    • Reducer is just pure functions that receive the previous state and action and return the new state
    • You can start with just a Reducer, but as the application gets bigger, you can break it down into smaller reducers that work independently on different parts of the state tree. Because Reducer is just a function, you can control the order in which they are called, pass in additional data, Even write reusable reducers to handle some common tasks, such as pagers

Combine React and Redux

  • We talked about Redux, which is very pure and simple
  • In combination, can we use Redux on React with things we already have
  • Simply rerender when store. State changes
import ReactDOM from 'react-dom';
import { createStore } from 'redux';

function reducer(state = {
  count: 1
}, action) {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        count: state.count + 1
      }
    case 'MINUS':
      return {
        ...state,
        count: state.count - 1
      }
    default:
      return state
  }
}
const store = createStore(reducer);

function render() {
  ReactDOM.render(
    <div>
      <p>{store.getState().count}</p>
      <button onClick={()= > store.dispatch({ type: "ADD" })}>+1</button>
      <button onClick={()= > store.dispatch({ type: "MINUS" })}>-1</button>
    </div>.document.querySelector('#root'))}const unSubscribe = store.subscribe(() = > { // Listen to store. State change, rerender
  console.log(1);
  render()
});
render();
Copy the code

React-Redux

  • Use Redux in React. React.render is an inconvenience
  • Redux is a very monolithic state management library, and it wasn’t designed for React itself
  • We can use Redux in React, which is the Redux binding library in the React project, to make Redux use in React less tedious

The installation

npm i react-redux
Copy the code

Simple to use

  • Use the Provider component to wrap the entire application
    • The Provider consists of a store property
    • The imported stores can be referenced in the example above
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './app';
import { store } from './store'; // Store method example 1, export store, see above

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>.document.querySelector('#root'))Copy the code

Component to get redux’s store

Connect – Higher order component

  • Use the connect function to create a higher-order component (passing in the component, returning a new component) that the component needsstatedispatchTo the component
  • connect(callback)(Cmp)
    • Callback must have a return value of the object type that determines which parameters need to be passed to the component
    • Connect is called and returns a higher-order component
    • Connect is only a higher-order function, and the return value of connect is a higher-order component
    • The obtained state is available at props
function App(props) {
  const { count, dispatch } = props;
  return (
    <div>
      <p>{count}</p>
      <button onClick={()= > {
        dispatch({
          type: 'ADD'
        })
      }}>+1</button>
    </div>)}const newApp = connect(state= > {
  console.log(state);
  return {
    count: state.count
  }
})(App);

console.log(newApp);

export default newApp

// Together
// export default connect(state => ({ count: state.count }))(App)
Copy the code

Hooks

  • Every component that needs to use store needs to go through this list. This is a lot of trouble
  • Note that Hooks are added after react-redux7.x
    • useSelector– access to the state
      • Unlike Connect, which must return an object, it can return any type
    • UseDispatch – Obtains the dispatch
    • UseStore – Get store
import { useDispatch, useSelector, useStore } from "react-redux";

export default function App(props) {
  const count = useSelector(state= > state.count);
  const dispatch = useDispatch();
  const store = useStore();
  console.log(store);
  return (
    <div>
      <p>{count}</p>
      <button onClick={()= > {
        dispatch({
          type: 'ADD'
        })
      }}>+1</button>
    </div>)}Copy the code

PS

  • CombineReducers, applyMiddleware, etc.
  • But I have a new job to do, so I’ll write it when I can