react中Context以及useContext的使用

解决问题:在较深的组件树中如何进行数据的传递

Why:提出context的初衷

react中的数据在父子组件中一般以props形式传递,如果父组件要把某个数据传递给孙子或者重孙子组件,就要经过子组件层层传递,比较麻烦。为此引入context全局上下文,来实现数据跨组件共享

When:context的使用场合

  • 传给多个孙子组件
    推荐使用全局上下文,避免属性层层传递到多个孙子组件
    但也有副作用:组件的复用性变差
  • 传给单个孙子组件
    不建议使用context
    替代方案:如果是想避免多个属性层层传递给孙子组件,可以将直接孙子组件自身传递下去,那么中间组件就无需知道多余的props
    替代方案评价:
    好处:减少传递props数量,代码更干净
    坏处:逻辑提升到组件树的更高层级处理,高层组件变得复杂

How:如何使用context

🌰举例:设置主题色:黑色/白色
生产侧代码:useTheme.tsx文件⬇️

// 1 创建主题色上下文
const ThemeContext = React.createContext(undefined);
ThemeContext.displayName = 'ThemeContext';

// 2 创建Provider,同时设定value
// context会根据引用标识决定何时进行渲染,所以一个陷阱🪤,provider的父组件重新渲染时,可能会在consumers组件中触发意外的渲染
// 为了防止这种情况,需要将value状态提升到父节点的state中
const ThemeProvider = (children) => {
  const [theme, setTheme] = useState('light');

  return <ThemeContext.Provider value={theme, setTheme}>
    { children }
  </ThemeContext.Provider>
}

// 3 创建hooks
const useTheme = () => {
  const context = useContext(themeContext);
  if(!context){
    throw new Error ('useTheme必须在ThemeProvider中使用')
  }

  return context;
}

消费侧代码:
首先作为Provider的子组件使用

<Themeprovider>
  <ThemeBar/>
</Themeprovider>

其中ThemeBar中可以拿到全局数据theme

import React from 'react';

// theme变化,ThemeBar就重新渲染,所以不建议把很多属性耦合进入同一个Context中
// 要把经常变化的和不经常变化的分开,例如:ThemeContext就负责Theme
const ThemeBar = () => {
  const {theme, setTheme} = useTheme();

	return <div onClick={()=>setTheme('dark')}>{theme}<div>
}

Tips:性能浪费

当Provider的value变化时,内部所有消费组件都会重新渲染,并且useContext的传播不会受制于shouldComponentUpdate函数,所以父亲组件用了memo,但子组件是context的消费组件,当value变化时,也会重新渲染

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Context 结合 Reducer 可以实现状态管理和状态更新的功能。Reducer 是一个纯函数,接收当前的状态和一个 action,返回一个新的状态。通过 Context 和 Reducer 的结合使用,可以将状态和状态更新逻辑分离到不同的文件,使得组件的代码更加简洁和清晰。 下面是一个示例代码: ```jsx // 创建一个 context 对象 const MyContext = React.createContext(); // 定义 reducer 函数 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 ParentComponent() { const [state, dispatch] = useReducer(reducer, { count: 0 }); // 将 reducer 的 dispatch 函数作为属性传递给子组件 return ( <MyContext.Provider value={{ state, dispatch }}> <ChildComponent /> </MyContext.Provider> ); } // 子组件 function ChildComponent() { // 使用 useContext 钩子获取父组件提供的 context 对象 const { state, dispatch } = useContext(MyContext); return ( <div> <p>当前的计数:{state.count}</p> <button onClick={() => dispatch({ type: "increment" })}>增加</button> <button onClick={() => dispatch({ type: "decrement" })}>减少</button> </div> ); } ``` 在上面的代码,父组件使用 `useReducer` 钩子创建了一个状态以及一个 dispatch 函数。将状态和 dispatch 函数通过 Context 提供给子组件。在子组件,通过 `useContext` 钩子获取父组件提供的 state 和 dispatch 对象。当用户点击子组件的增加或减少按钮时,会调用 dispatch 函数并传入对应的 action 对象,从而触发状态更新,更新后的状态会自动传递给所有使用了该 Context 的组件,实现了状态的管理和更新。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值