useContext
为了实现祖孙组件的便捷通信,不使用繁琐的props和ref层层传递信息,可以使用Hooks组件的context特性实现通信
步骤
-
根目录下使用
createContext
创建一个上下文对象,用来管理上下文中的信息src/ThemeContext.js
// 创建上下文对象 import { createContext } from 'react'; const ThemeContext = createContext(); export default ThemeContext;
-
让祖先组件具备状态和修改状态的方法。将所有后代组件包裹到
上下文对象.Provider
中,通过value
对象存储上下文中共享的数据和方法,祖先组件更新时会往上下文中放入最新的共享内容 -
在后代组件中使用
useContext
解构上下文对象获取上下文信息。
注意:
上下文操作的核心是上下文对象,如ThemeContext。创建多个不同的上下文对象,可以基于不同上下文对象中的Provider存放不同的上下文信息,同时也可以基于不同的上下文对象,获取指定上下文中的信息
在子组件Main和Footer中获取父组件属性和方法
import React, { useContext, useMemo, useState } from 'react'
import { PropTypes } from 'prop-types';
import { Button } from 'antd';
// 3.导入上下文对象
import ThemeContext from 'src/ThemeContext';
export default function ContextCommunication() {
// 2.祖先组件具备状态和修改状态的方法
const [supNum, setSupNum] = useState(0);
const [oppNum, setOppNum] = useState(0);
const changeHandler = (type) => {
return () => {
switch (type) {
case 'sup':
setSupNum(supNum + 1);
break;
case 'opp':
setOppNum(oppNum + 1);
break;
default:
break;
}
}
}
// 4.将所有后代组件包裹到上下文对象的Provider中,通过value对象存储上下文中共享的数据和方法
// 祖先组件更新时会往上下文中放入最新的共享内容
return <ThemeContext.Provider value={{
supNum,
oppNum,
changeHandler
}}>
<div className='vote'>
<div className="header"></div>
<Main />
<Footer />
</div>
</ThemeContext.Provider>
}
const Main = () => {
// 5.解构useContext(context对象)返回值
const { supNum, oppNum } = useContext(ThemeContext);
// 数据缓存,类似vue计算属性
const totalNum = useMemo(() => {
return supNum + oppNum;
}, [supNum, oppNum])
return <div className='vote-main'>
<ul>
<li>支持人数:<span>{supNum}</span></li>
<li>反对人数:<span>{oppNum}</span></li>
<li>支持比率:<span>{totalNum ? (supNum / totalNum * 100).toFixed(2) + '%' : '--'}</span></li>
</ul>
</div>
}
const Footer = () => {
const { changeHandler } = useContext(ThemeContext)
return <div className='vote-footer'>
{/* 传参一:高阶函数 currying */}
<Button onClick={changeHandler('sup')} type='primary'>支持</Button>
<Button onClick={changeHandler('opp')} type='warn'>反对</Button>
{/* 传参二:非高阶 合成函数 回调 */}
{/* 传参三:bind
<button onClick={change.bind(null, 'sup')}>支持</button>
<button onClick={change.bind(null, 'opp')}>反对</button>
*/}
</div>
}