目录
作用:
createContex + useReducer 约等于 redux
createContext的作用: 跨组件通信
useReducer的作用: 存储数据,通过dispatch改变数据
createContext 的使用步骤:
1,在context.ts 创建Context对象
import { createContext } from "react";
// 1. 创建Context对象
export default createContext({} as any);
2, 在Provider.tsx中
1)导入context.ts
2)Provider来包裹后代组件,跨组件传递数据
在Provider.tsx创健Provider,也就是context.Provider,提供数据contextValue
数据contextValue 由useReducer提供并且管理(后续讲)
import React, { useReducer, useMemo, createContext } from 'react';
import context from './context';
import reducer from './reducer';
import initial from './initial';
export default ({children}: any) => {
const [state, dispatch] = useReducer(reducer, initial);
const contextValue = useMemo(() => ({
state,
dispatch,
}), [
state
]);
return (
<context.Provider
value={contextValue}
>
{children}
</context.Provider>
);
}
3.被provider包裹的组件如何拿到数据呢?--跨组件通信
1)通过Provider 包裹后代组件
--1, 导入Provider
--2,被Provider包裹的组件都嫩拿到contextValue的数据
---3 包裹的组件:Son1 (Son1里面还有Son2)
import React, { useContext } from 'react'
import './App.less'
import {Son1} from './Son1'
import Provider from './context/Provider'
import context from './context/context'
export const Header:React.FC =() => {
const {dispatch, state} = useContext(context)
console.log(state); //undefined 注意此组件不能拿到数据,因为没有被Provider包裹
return (
<>
<Provider>
<div className='head'>
<span>我最大</span>
<Son1></Son1>
</div>
</Provider>
</>
)
}
2)后代组件如何拿到数据
--1,导入context.ts
--2,通过useContext 拿到数据state即可
import React, { useContext } from 'react'
import './App.less'
import { Son2 } from './Son2'
import context from './context/context'
export const Son1:React.FC =() => {
const {dispatch, state} = useContext(context)
return (
<>
<div className='Son1'>
<div>我是Son1,我也拿到值:{state.numberValue}</div>
<Son2></Son2>
</div>
</>
)
}
useReducer的使用步骤:
1)在initial创建初始数据state
//准备初始数据
export default {
numberValue: 0,
};
2)创建reducer
state 就是初始数据,action为dispatch的action,dispatch(action)
action为 {type:xxx, payload: xxx }
export default (state: any, action: any) => {
switch (action.type) {
case "change2":
return {
...state,
numberValue: action.payload
};
default:
return {
...state,
numberValue:222
};
}
}
3)在Provider中,创建useReducer
useReducer有2个参数,参数1 为reducer,参数2 为初始数据
拿到初始数据与dispatch,我们可以把数据传递给后代组件
import React, { useReducer, useMemo, createContext } from 'react';
import context from './context';
import reducer from './reducer';
import initial from './initial';
export default ({children}: any) => {
const [state, dispatch] = useReducer(reducer, initial);
const contextValue = useMemo(() => ({
state,
dispatch,
}), [
state
]);
return (
<context.Provider
value={contextValue}
>
{children}
</context.Provider>
);
}
4)看看如何通过dispatch改变数据的
点击按钮,dispatch派遣action,即可改变数据,组件也拿到了改变后的数据
import React, { useContext } from 'react'
import './App.less'
import context from './context/context'
export const Son2:React.FC =() => {
const value = useContext(context)
console.log('value',value);//{ dispatch, state: {numberValue: ?} }
const {dispatch, state:{numberValue}} = value
const addNumber = () => {
dispatch({
type:'change2',
payload:2
})
}
return (
<>
<div className='Son2'>
我是Son2, Provider中的值{numberValue}
<button onClick={addNumber}>点击变成2 </button>
</div>
</>
)
}
点击后
优化:对reducer进行分类封装
chang2.ts
export default (state: any, action: any) => {
state.numberValue = action.payload
return state;
}
index.ts
import change2 from './change2';
export default{
change2,
}
reducer.ts
//写法1,直接写
// export default (state: any, action: any) => {
// switch (action.type) {
// case "change2":
// return {
// ...state,
// numberValue: action.payload
// };
// default:
// return {
// ...state,
// numberValue:222
// };
// }
// }
//写法2,用写法1注解下面的写法2即可
import lodash from 'lodash';
import reducers from './reducers'
import produce from 'immer'
interface Reducers {
[key: string]: (state: any, action: any) => any;
}
export default (state: any, action: any) => {
const reducer = (reducers as Reducers)[action.type];
//拿到函数
// const reducer = (state: any, action: any) => {
// state.numberValue = action.payload
// return state;
// }
if (lodash.isFunction(reducer)) {
return produce(state, (draftState: any) => {
//复制state为draftState ,传入reducer中
return reducer(draftState, action)
});
}
return state;
};
- 页面state简单,可以直接使用
useState
- 页面state复杂,state是一个对象或者state非常多散落在各处, 使用
userReducer
- 页面组件层级比较深,并且需要子组件触发state的变化,可以考虑
useReducer
+useContext