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;
消费者
消费者有两种消费模式 useContent
或 Store.Consumer
- 使用
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