A prelude to

Use the react – story

Why use it?

React-redux is not a very advanced way to write things like render and getState.

The installation

yarn add react-redux

Two apis are provided

  1. Provider provides stores for descendant components
  2. Connect provides data and change methods for components

API

  • <Provider store>

Enable connect() methods at the component level to obtain the Redux store. Normally, your root component should be nested within to use the connect() method.

  • connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options])

Connect the React component to the Redux Store. Returns a new component class connected to the Redux Store.

use

Provides store, index.js globally

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {Provider} from 'react-redux';
//import {Provider} from './reactKredux';
import store from './store';


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

Get status data, reactreduxPage.js

import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; // Use react-redux,connect const ReactReduxPage = (props) => {let {count, add, minus} = props; Return (< div > < h3 > ReactReduxPage < / h3 > < p > {count} < / p > < button onClick = {() = > {the add ()}} > add < / button > < button onClick = {() => {minus()}}> </button> </div>)} export default connect(//mapStateToProps) ({count}), //mapDispatchToProps object|function (dispatch) => { let result = { add: () => ({type: 'ADD'}), minus: () => ({type: 'MINUS'}) } result = bindActionCreators(result, dispatch); return {dispatch, ... result} } )(ReactReduxPage)Copy the code

BindActionCreators is a function that binds the Action with a dispatch method, which is equivalent to Dispatch ({type: ‘ADD’}), otherwise dispatch will not be triggered and therefore data will not be updated. Connect is equivalent to a higher-order component, passing in a component and returning a new component with a store after processing the incoming parameters. The redux document looks like this:

The core

Handwriting implementation of React-redux

Create the reactKredux.js file to implement:

  • [ bindActionCreators ]
  • [ Provider ]
  • [ connect ]

bindActionCreators

Take a look at the Implementation of bindActionCreators,reactKredux.js

const bindActionCreator = (action, dispatch) => { return (... args) => (dispatch(action(... args))) } const bindActionCreators = (actions, dispatch) => { let bindActions = {}; for (let key in actions) { bindActions[key] = bindActionCreator(actions[key], dispatch); } console.log(bindActions); return bindActions }Copy the code

The code is short and the implementation is simple. It defines a function that takes two arguments: Actions,dispatch, and returns an internal property that returns the object wrapped by Dispatch as follows:

Provider

Provider implementation,reactKredux.js

The import {useContext createContext, useEffect useReducer, useState, useCallback} from 'react' / / react transfer data across hierarchy context; // 1. Create Context; let Context = createContext(); //2.Provider pass value const Provider = ({store, children}) => { return <Context.Provider value={store}> {children}</Context.Provider> }Copy the code

React Passes data across hierarchies. There are three steps to use Context:

  1. Create Context, createContext ()
  2. Provider passes value, < context. Provider value={}>
  3. Child components consume Context values

    There are three ways of consumption:
    1. ContextType (used only in class components, subscribing only to the source of a single context)
    2. UseContext (only for function components and custom hooks)
    3. Consumer (unlimited, can be used in both components)

Use Provider to pass data store, index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// import {Provider} from 'react-redux';
import {Provider} from './reactKredux';
import store from './store';
ReactDOM.render(
    <Provider store={store}><App/></Provider>,
    // <App/>,
    document.getElementById('root')
);
Copy the code

App page, app.js

import './App.css';
import  ReactRudexPage from './pages/ReactReduxPage';
import  ReactRudxHookPage from './pages/ReactReduxHookPage';
// import store from './store';

function App() {
  return (
    <div className="App">
      {/*<ReactRudxHookPage/>*/}
        <ReactRudexPage/>

    </div>
  );
}

export default App;
Copy the code

Connect

An implementation of Connect,reactKredux.js

Const connect = (mapStateToProps, mapDispatchToProps) => WrappedComponent => (props) => { So use useContext to get the value of the Context, store.let store = useContext(Context); Const {getState, subscribe,subscribe} = store; let mapStates, mapdispatch = {dispatch}; mapStates = mapStateToProps(getState()); if (typeof mapDispatchToProps === 'object') { mapdispatch = bindActionCreators(mapDispatchToProps, dispatch); } else { mapdispatch = mapDispatchToProps(dispatch); } // const [count, forceUpdate] = useReducer(x => x + 1, 0); // forceUpdate const forceUpdate=useForceUpdata(); UseEffect (() => {const unSubscribe = subscribe(() => forceUpdate())); Return () => {unSubscribe()}}, [store]) return <NewComponent {... props} {... mapStates} {... mapdispatch} /> } const useForceUpdata=()=>{ const [state,setState]=useState(0); const forceUpdate=useCallback(()=>{setState((pre)=>pre+1)},[]); return forceUpdate; }Copy the code
  • Connect is a function, External accept parameters: mapStateToProps mapDispatchToProps, internal accept parameters: WrappedComponent (components of the use of the current store), WrappedComponent accept parameters: props (component own props) . A new, polished component is returned.

  • MapStateToProps is a function that accepts all the state values in a Store, obtained with store.getState. Return the desired state value,({count}) => ({count}), so just call mapStateToProps(getState()).

  • The mapDispatchToProps can be a function or an object, so the type is determined first. If it is an object, the bindActionCreators app is used to return a dispatch processed new object. If it is a function, call the function directly, passing in the argument dispatch

  • Subscribe without this step, the interface cannot update the status value; Subscribe (() => forceUpdate())); subscribe(() => forceUpdate()); Store triggers forceUpdate(), at which point the component is updated.

  • Finally, the component needs to unSubscribe before unSubscribe, which triggers unSubscribe(). This is the store’s subscribe return operation, which deletes the corresponding subscription.

Index. Js and ReactReduxPage. Facing the connect in js, bindActionCreators, the introduction of the Provider, for our own writing, is as follows: index. Js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// import {Provider} from 'react-redux';
import {Provider} from './reactKredux';
import store from './store';


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

ReactReduxPage.js

// import {connect} from 'react-redux'; // import {bindActionCreators} from 'redux'; import {bindActionCreators,connect} from '.. // Function components using react-redux,connect const ReactReduxPage = (props) => {let {count, add, minus} = props; Return (< div > < h3 > ReactReduxPage < / h3 > < p > {count} < / p > < button onClick = {() = > {the add ()}} > add < / button > < button onClick = {() => {minus()}}> </button> </div>)} export default connect(//mapStateToProps) ({count}), //mapDispatchToProps object|function (dispatch) => { let result = { add: () => ({type: 'ADD'}), minus: () => ({type: 'MINUS'}) } result = bindActionCreators(result, dispatch); return {dispatch, ... result} } )(ReactReduxPage)Copy the code

This is the store file, store/index.js

import {createStore, combineReducers} from 'redux';

export const countReducer = (state = 0, action) => {
    switch (action.type) {
        case 'ADD':
            return state + 1;
        case 'MINUS':
            return state-1;
        default:
            return state;
    }
}
//
const store = createStore(combineReducers({count:countReducer}));
// const store = createStore(countReducer);
export default store;
Copy the code

Take a look at the final result:



The end result is the same

React-redux Hooks API and handwritten implementation

use

Two apis: useSelector gets store State useDispatch Gets Dispatch reactreduxhookPage.js

import {useCallback} from "react"; import {useDispatch, useSelector} from "react-redux"; // import {useDispatch, useSelector} from ".. /reactKredux"; export default({value})=>{ const dispatch=useDispatch(); const count=useSelector(({count})=>count); console.log(count); return ( <div> <h3>ReactReduxHookPage</h3> <p>{count}</p> <button The onClick = {useCallback (() = > {dispatch ({type: 'ADD'})}, [])} > ADD < / button > < button OnClick = {useCallback (() = > {dispatch ({type: "MINUS"})}, [])} > MINUS < / button > < / div >)}Copy the code

Redux = “redux”; redux =” redux”; redux = “redux”; The pages in app.js refer to the ReactReduxHookPage component. As follows: ReactReduxHookPage. Js

import './App.css';
import  ReactRudexPage from './pages/ReactReduxPage';
import  ReactRudxHookPage from './pages/ReactReduxHookPage';
// import store from './store';

function App() {
  return (
    <div className="App">
      <ReactRudxHookPage/>
      {/*  <ReactRudexPage/>*/}

    </div>
  );
}

export default App;
Copy the code

The last pass was as follows:

Handwritten implementation

reactKredux.js

//hooks //get const useSelector = (select) => { const store = useStore(); const getState=store.getState(); // const [count,forceUpdate]=useReducer((x)=>x+1,0); const forceUpdate=useForceUpdata(); useEffect(()=>{ const unSubScribe=store.subscribe(()=>forceUpdate()); return ()=>{ unSubScribe(); } },[store]) return select(getState); } //set const useDispatch = () => { const store = useStore(); return store.dispatch; } // Get store const useStore = () => {return store const store = useContext(Context); return store; } const useForceUpdata=()=>{ const [state,setState]=useState(0); const forceUpdate=useCallback(()=>{setState((pre)=>pre+1)},[]); return forceUpdate; }Copy the code

UseSelector and useDispatch are equivalent to get and set. UseSelector: GetState takes a function argument, which in turn takes a getState argument and returns the desired state value. GetState is obtained from store, as in store.getState, which is obtained from useContent. So what you’re doing is you’re just calling this function with the parameter select and passing in the parameter getState. Finally return. And inside do subscribe and unsubscribe.

UseDispatch: reactKredux.js useDispatch: reactKredux.js useDispatch: ReactKredux.js useDispatch: ReactKredux.js useDispatch: ReactKredux.js useDispatch: ReactKredux.js

The import {useContext createContext, useEffect useReducer, useState, useCallback} from 'react' / / react transfer data across hierarchy context; // 1. Create Context; let Context = createContext(); //2.Provider pass value const Provider = ({store, children}) => { return <Context.Provider value={store}> {children}</Context.Provider> } // 3. Consumption Context value // Three consumption methods: // 1) can only be used with class components :contextType, can only subscribe to a single context // 2) can only be used with function components useContext // 3) Can be used with class components Consumer const connect = (mapStateToProps, mapDispatchToProps) => WrappedComponent => (props) => { So use useContext to get the value of the Context, store.let store = useContext(Context); Const {getState, subscribe,subscribe} = store; let mapStates, mapdispatch = {dispatch}; mapStates = mapStateToProps(getState()); if (typeof mapDispatchToProps === 'object') { mapdispatch = bindActionCreators(mapDispatchToProps, dispatch); } else { mapdispatch = mapDispatchToProps(dispatch); } // const [count, forceUpdate] = useReducer(x => x + 1, 0); // forceUpdate const forceUpdate=useForceUpdata(); UseEffect (() => {const unSubscribe = subscribe(() => forceUpdate())); Return () => {unSubscribe()}}, [store]) return <NewComponent {... props} {... mapStates} {... mapdispatch} /> } const bindActionCreator = (action, dispatch) => { return (... args) => (dispatch(action(... args))) } const bindActionCreators = (actions, dispatch) => { let bindActions = {}; for (let key in actions) { bindActions[key] = bindActionCreator(actions[key], dispatch); } console.log(bindActions); return bindActions } //hooks //get const useSelector = (select) => { const store = useStore(); const getState=store.getState(); // const [count,forceUpdate]=useReducer((x)=>x+1,0); const forceUpdate=useForceUpdata(); useEffect(()=>{ const unSubScribe=store.subscribe(()=>forceUpdate()); return ()=>{ unSubScribe(); } },[store]) return select(getState); } //set const useDispatch = () => { const store = useStore(); return store.dispatch; } // Get store const useStore = () => {return store const store = useContext(Context); return store; } const useForceUpdata=()=>{ const [state,setState]=useState(0); const forceUpdate=useCallback(()=>{setState((pre)=>pre+1)},[]); return forceUpdate; } export {bindActionCreators, connect, Provider,useSelector,useDispatch};Copy the code

The end

(PS: write technical blog for the first time, recently study source code, record some. Deepen your impression and exercise your ability to express yourself. There may be many inadequacies and omissions in it. I hope you can give me more guidance and point out.