美文网首页
react深入2 - react-redux

react深入2 - react-redux

作者: 申_9a33 | 来源:发表于2022-02-03 20:30 被阅读0次

    1.react-redux使用

    1.1 安装

    npm i redux
    npm i react-redux

    1.2 创建一个store

    // src\store\index.ts
    
    import { createStore, Action } from 'redux';
    
    function countReducer(count:number = 0, action:Action) {
      switch (action.type) {
        case 'ADD':
          return count + 1;
    
        case 'MINUS':
          return count - 1;
        default:
          return count;
      }
    }
    
    export default createStore(countReducer);
    

    1.3 Provider 提供给全局组件使用

    // src\main.tsx
    
    import React from 'react';
    import { render } from 'react-dom';
    import { Provider } from 'react-redux';
    import store from './store';
    import ClassPage from './view/ClassPage';
    
    function App() {
      return (
        <div>
          <Provider store={store}>
            <ClassPage />
          </Provider>
        </div>
      );
    }
    
    render(<App />, document.getElementById('root'));
    

    1.4 子class 组件使用

    // src\view\ClassPage.tsx
    
    import React, { Component } from 'react';
    import { connect } from 'react-redux';
    
    // eslint-disable-next-line react/prefer-stateless-function
    class ClassPage extends Component {
      render(): React.ReactNode {
        console.log(this.props);
        // eslint-disable-next-line react/prop-types
        const { count, add, minus } = (this.props as any);
        return (
          <div>
            <p>{count}</p>
            <button onClick={() => add()} type="button">add</button>
            <button onClick={() => minus()} type="button">minus</button>
          </div>
        );
      }
    }
    
    export default connect(
      (count:number) => ({ count }),
      (dispatch) => {
        const add = () => dispatch({ type: 'ADD' });
        const minus = () => dispatch({ type: 'MINUS' });
        return {
          add,
          minus,
          dispatch,
        };
      },
    )(ClassPage);
    
    

    2.实现自己的 react-redux

    // src\react-redux\index.tsx
    
    import React, { useContext, useLayoutEffect, useReducer } from 'react';
    
    // 创建一个用于存放store的上下文
    const Context = React.createContext(undefined);
    const StoreProvider = Context.Provider;
    
    export function Provider({ store, children }:any) {
      return <StoreProvider value={store}>{children}</StoreProvider>;
    }
    
    function useForceUpdate() {
      const [,forceUpdate] = useReducer((i) => i + 1, 0);
    
      return () => forceUpdate();
    }
    // eslint-disable-next-line max-len
    export const connect = (mapStateToProps:any, mapDispatchToProps:any) => (WrappedComponent:any) => (props:any) => {
      const store = useContext(Context) as any;
    
      const forceUpdate = useForceUpdate();
    
      const stateProps = mapStateToProps(store.getState());
    
      let dispatchProps:any = {};
    
      if (typeof mapDispatchToProps === 'function') {
        dispatchProps = mapDispatchToProps(store.dispatch);
      } else {
        // eslint-disable-next-line no-restricted-syntax
        for (const key in mapDispatchToProps) {
          if (Object.prototype.hasOwnProperty.call(mapDispatchToProps, key)) {
            dispatchProps[key] = (...args:any) => store.dispatch(mapDispatchToProps[key](...args));
          }
        }
      }
    
      useLayoutEffect(() => {
        const unsubscribe = store.subscribe(() => {
          forceUpdate();
        });
        return () => unsubscribe();
      }, [forceUpdate, store]);
    
      // eslint-disable-next-line react/jsx-props-no-spreading
      return <WrappedComponent {...props} {...stateProps} {...dispatchProps} />;
    };
    
    export default {};
    

    3.hook 中使用 react-redux

    import React, { useCallback } from 'react';
    import { useSelector, useDispatch } from 'react-redux';
    
    export default function FunctionPage() {
      const num = useSelector((count:number) => count);
      const dispatch = useDispatch();
    
      const add = useCallback(() => {
        dispatch({
          type: 'ADD',
        });
      }, [dispatch]);
    
      return (
        <div>
          <p>{num}</p>
          <button onClick={() => add()} type="button">add</button>
        </div>
      );
    }
    

    4 hooks useSelector useDispatch实现

    // src\react-redux\index.tsx
    
    // hooks
    export function useSelector(selector:any) {
      const forceUpdate = useForceUpdate();
      const store = useContext(Context) as any;
      const selectorState = selector(store.getState());
    
      useLayoutEffect(() => {
        const unsubscribe = store.subscribe(() => {
          forceUpdate();
        });
        return () => unsubscribe();
      }, [forceUpdate, store]);
    
      return selectorState;
    }
    
    export function useDispatch() {
      const store = useContext(Context) as any;
    
      return store.dispatch;
    }
    

    源码

    相关文章

      网友评论

          本文标题:react深入2 - react-redux

          本文链接:https://www.haomeiwen.com/subject/odxjkrtx.html