使用 createContext 和 useReducer 替换 Redux

    React 及其依赖版本需要升级到 v16.8.0 以上

    我们以全局消息为例, 实现这个功能

    创建 Store

    Redux 类似,创建一个全局的 Store ,

    store.js

    import React, {createContext, useReducer} from 'react';
    // Store 默认值
    const defaultValue = {
        message: {open: false, variant: 'success', content: ``, direction: 1000},
    };
    // 创建 Store
    export const Store = createContext(defaultValue);
    const reducer = (state, action) => {
        switch(action.type) {
            case 'message':
                return {...state, message: action.payload};
            default:
                return state
        }
    }
    // 作为父组件挂在Store
    const StoreProvider = props => {
        const [store, dispatch] = useReducer(reducer, defaultValue);
        return (
            <Store.Provider value={{...store, dispatch}}>
                {props.children}
            </Store.Provider>
        );
    };
    export default StoreProvider;
    

    挂载Store

    index.js 中挂载 Store

    index.js

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    import Store from './store'
    ReactDOM.render(
      <Store>
          <App/>
      </Store>,
      document.getElementById('root')
    );
    

    挂载生产者,消费者

    将消息组件 message 作为 消费者 。挂载到 React 的根组件 App.js
    发送消息的组件 Content 作为 生产者 作为同级挂载到同级的叶子组件上(即 React 的根组件 App.js)。

    尽量不要把 生产者(dispatch) 和 消费者 挂载到同一个组件树中,这样可能会导致无限更新,触发栈溢出异常 Maximum call stack size exceeded...

    App.js

    import React from 'react';
    import Content from "./content"
    import Message from "./message";
    export default function App() {
      return (
        <React.Fragment>
          <Content/>
          <Message/>
        </React.Fragment>
      );
    }
    

    生产者

    content,js

    import React, {useEffect} from 'react';
    import {Store} from "../../utils/store";
    const Content = () => {
        const {dispatch} = React.useContext(Store);
        useEffect(() => {
                dispatch({
                    type: 'message',
                    payload: {open: true, content: `This is a test Message`}
                })
            }
         }, []);
        return null
    }
    export default Content;
    

    消费者

    消费者有两种消费模式 useContentStore.Consumer

    1. 使用 useContent 消费
      message.js
    import React, {useContext} from 'react';
    import Snackbar from '@material-ui/core/Snackbar';
    import SnackbarContent from '@material-ui/core/SnackbarContent';
    import {Store} from "../utils/store";
    
    const Message = () => {
       //获取全局的message对象
      const {message} = useContext(Store);
      const {content, open} = message;
      return (
        <Snackbar open={open}>
          <SnackbarContent message={content}/>
        </Snackbar>
      );
    }
    export default Message;
    

    2.使用 Store.Consumer 消费
    message.js

    import React from 'react';
    import Snackbar from '@material-ui/core/Snackbar';
    import SnackbarContent from '@material-ui/core/SnackbarContent';
    import {Store} from "../utils/store";
    
    const Message = () => {
      return (
         <Store.Consumer>
         { 
           ({message}) =>     
           <Snackbar open={message.open}>
                <SnackbarContent message={message.content}/>
           </Snackbar>
         }
         </Store.Consumer>
      );
    }
    export default Message;
    

    一个真实世界的Demo

    一个真实世界的Demo: https://jansora.com

    一个真实世界的Demo 的源代码: https://github.com/Jansora/pancake

    评论栏