useContext和useReducer
可以用于多层组件的之间的传值。接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定
当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。即使祖先使用 React.memo 或 shouldComponentUpdate,也会在组件本身使用 useContext 时重新渲染
import React, { useContext, createContext } from 'react';
const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
const ThemeContext = createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}
export default App;
在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</>
);
}
export default Counter;
3. 用 useContext + useReducer 替代 redux
import React from 'react';
import ReactDOM from 'react-dom';
import ShowArea from './redux-test/ShowArea';
import Buttons from './redux-test/Buttons';
import { Color } from './redux-test/Color';
ReactDOM.render(
<React.StrictMode>
<>
<Color>
<ShowArea />
<Buttons />
</Color>
</>
</React.StrictMode>,
document.getElementById('root'),
);
import React, { createContext,useReducer } from "react";
export const ColorContext = createContext({});
export const UPDATE_COLOR = "UPDATE_COLOR"
const reducer = (state, action) => {
switch(action.type) {
case UPDATE_COLOR:
return action.color
default:
return state
}
}
export const Color = props => {
const [color, dispatch] = useReducer(reducer, 'blue')
return (
<ColorContext.Provider value={{ color,dispatch }}>
{props.children}
</ColorContext.Provider>
);
};
import React,{useContext} from 'react'
import { ColorContext } from "./Color";
const ShowArea = (props) => {
const { color } = useContext(ColorContext);
return (
<div style={{color}}>字体颜色展示为{color}</div>
)
}
export default ShowArea
import React, { useContext } from "react";
import { ColorContext, UPDATE_COLOR } from "./Color";
const Buttons = props => {
const { dispatch } = useContext(ColorContext);
return (
<React.Fragment>
<button onClick={() => {
dispatch({ type: UPDATE_COLOR, color: "red" });
}}>红色</button>
<button onClick={() => {
dispatch({ type: UPDATE_COLOR, color: "yellow" });
}}>黄色</button>
</React.Fragment>
);
};
export default Buttons;
参考地址
用 useContext + useReducer 替代 redux
|