useContext用法+切换主题小示例+对象型字面量传递的优化

react中父子组件传递参数我们一般使用Props,但是碰到多层传递或者兄弟组件传递的时候,每层的组件都需要声明参数进行层级传递,增加代码复杂程度的同时也不利于代码逻辑的维护。这时候我们就可以使用context进行参数传递了。

Context的作用就是对它所包含的组件树提供全局共享数据的一种技术。

我们以一个主题色的调用来展现一下useContext的使用方法

1.定义主题颜色

const themes = {
    light: {
        foreground: '#000',
        background: '#eee'
    },
    dark: {
        foreground: '#fff',
        background: '#666'
    }
}

2.使用createContext来初始化

const ThemeContext = createContext(themes.light)

3.创建三个组件来展示参数传递

// 主题应用组件
const ThemeContent= () => {
	return <div>This is ThemeContent</div>
}
// 这层暂时仅仅用于传递
const Toolbar = () => {
	return <ThemeContent></ThemeContent>
}
// 这层为父组件
export const ContextDemo = () => {
	return <Toolbar></Toolbar>
}

4.在顶层(父组件)中创建provider组件

使用context创建的ThemeContext.Provider来包裹组件,将主题色作为value值传递
export const ContextDemo = () => {
 <ThemeContext.Provider value={theme.light}>
	<Toolbar></Toolbar>
 </ThemeContext.Provider>
}

5.在孙子组件中使用useContext导入ThemeContext,然后取出value值,应用于组件之中

useContext 函数接收的参数对象是 context 自身

const ThemeContent = () => {
    const themeStyle = useContext(ThemeContext)

    return (<div>
        <div style={{ background: themeStyle.background, color: themeStyle.foreground }}>
            hello world
        </div>
    </div>)

}

然后我们发现,主题应用已经生效了哈
在这里插入图片描述
接下来我们实现一键更换主题!

我们已经知道,在孙子组件中应用的主题颜色是父组件传递过来的,那么我们要更改的就是父组件provider处传递的value值 ,在父组件中我们的value是直接传递的theme.light,那么我们想改变它,只需要用useState就可以了!

是的,你没看错,改变useContext的值用useState。。。

使用useState改变useContext的值

方法1:在父组件添加主题切换方法和触发元素
export const ContextDemo = () => {
	/*  1.使用useState创建一个新变量,赋初主题值*/
    const [themeStyle, setThemeStyle] = useState(themes.dark)  
    console.log('themes.dark', themes.dark)
    
	/* 2.添加一个切换方法*/
    const toggleTheme = () => { 
        setThemeStyle(style => style === themes.dark ? themes.light : themes.dark)
    }

    return (
        <ThemeContext.Provider value={ themeStyle }> /*  传递多参数要用{{}}括起来哦*/
            <Toolbar></Toolbar>
            /*  3.添加一个按钮绑定此方法*/
            <button onClick={() => toggleTheme()}>change theme</button> 
        </ThemeContext.Provider>
    )
}

其他组件不需要动哦,父组件改变状态后会自动传递主题参数并渲染的~

方法2:在父组件添加主题切换方法,将方法传递到孙子组件,在孙子组件触发
export const ContextDemo = () => {
	/*  1.使用useState创建一个新变量,赋初主题值*/
    const [themeStyle, setThemeStyle] = useState(themes.dark)  
    console.log('themes.dark', themes.dark)
    
	/* 2.添加一个切换方法*/
    const toggleTheme = () => { 
        setThemeStyle(style => style === themes.dark ? themes.light : themes.dark)
    }

    return (
        <ThemeContext.Provider value={{ themeStyle, toggleTheme }}> /*  传递多参数要用{{}}括起来哦*/
            <Toolbar></Toolbar>
        </ThemeContext.Provider>
    )
}

/* 4.取出参数传递的切换方法并绑定在元素上*/
const ThemeContent = () => {
    const { themeStyle, toggleTheme } = useContext(ThemeContext)
    console.log(66666666666, themeStyle, toggleTheme)

    return (<div>
        <div style={{ background: themeStyle.background, color: themeStyle.foreground }}>
            hello world
        </div>

        <button onClick={() => toggleTheme()}>change theme</button> 
    </div>)

}

在这里插入图片描述
在这里插入图片描述
我们看到是可以正常切换的哈~

存在于Provider 组件下的子组件在context 的值发生变化后,都会重新渲染,这样可能会引发一些性能问题,我们可以通过 memo 去避免一些不必要的重渲染

 const ThemeContent = memo(() => {
    const { themeStyle, toggleTheme } = useContext(ThemeContext)
    console.log(66666666666, themeStyle, toggleTheme)

    return (<div>
        <div style={{ background: themeStyle.background, color: themeStyle.foreground }}>
            hello world
        </div>

        <button onClick={() => toggleTheme()}>change theme</button> 
    </div>)

})

Content是通过新旧值检测来确定变化,使用了与 Object.is 相同的算法
如果传给Content是个字面对象的话,有可能每次值的检测都会值得子组件重新渲染

上面我们的例子中,就是传递的themeStyle对象,只有每次使用setThemeStyle改变的时候才会触发重新渲染,如果我们使用诸如下边的字面量对象传递

export const ContextDemo = () => {
	/*  1.使用useState创建一个新变量,赋初主题值*/
    const [themeColor, setThemeColor] = useState('dark')  
    
	/* 2.添加一个切换方法*/
    const toggleTheme = () => { 
        setThemeColor(color=> color=== 'dark' ? 'light' : 'dark')
    }

    return (
        <ThemeContext.Provider value={{ themeColor }}> /*  传递多参数要用{{}}括起来哦*/
            <Toolbar></Toolbar>
            /*  3.添加一个按钮绑定此方法*/
            <button onClick={() => toggleTheme()}>change theme</button>
        </ThemeContext.Provider>
    )
}

const ThemeContent = () => {
    const { themeColor } = useContext(ThemeContext)
    console.log(66666666666, themeStyle, toggleTheme)

    return (<div>
        <div style={{ background: themes[themeColor].background, color: themes[themeColor].foreground }}>
            hello world
        </div>
    </div>)

}

在ContextDemo中,我们定义一个color state,然后使用{{ color }}传递,这个color其实是{{color: color}}的简写,意味着我们每次color变化都要赋值给一个对象,key和value都是color,这样每次我们主题颜色变化的时候都多了一次赋值操作,所以每次渲染时,这个属性都会是一个全新的对象,与之前的属性值进行===比较将得到false,提供给context的也都是一个新的字面量对象,导致孙子组件ThemeContent每次都会在父组件的渲染中跟着去重新渲染

所以解决办法就是我们先生成一个用来存储所有的style对象

 const [themeStyle, setThemeStyle] = useState(themes.dark)  

同样的,我们的style也优化成这样

<div style={{ background: themes[themeColor].background, color: themes[themeColor].foreground }}>
     hello world
</div>

不过在正常小型项目开发中,我们的行内样式style 一般也都是直接去赋值的,毕竟行内样式的改变不是那么的频繁~

这个例子只是一个最简单的例子,帮助能帮助到大家一起学习useContext的使用。还有对象字面量型props、context的优化~ 如果有不对的,还请大家温柔指正哦~

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单的示例: 首先,我们需要创建一个 Context 对象,可以在任何地方访问它。例如: ``` import React from "react"; const ThemeContext = React.createContext("light"); export default ThemeContext; ``` 在这个例子中,我们创建了一个名为 ThemeContextContext 对象,并将其默认值设置为 "light"。 接下来,我们需要在应用程序中的某个地方提供所创建的 Context 对象。例如: ``` import React from "react"; import ThemeContext from "./ThemeContext"; function App() { return ( <ThemeContext.Provider value="dark"> { /* 在这里渲染子组件 */ } </ThemeContext.Provider> ); } export default App; ``` 在这个例子中,我们在 App 组件中提供了 ThemeContext.Provider,并将其值设置为 "dark"。这意味着在主题上下文中,所有子组件都可以访问到的值为 "dark"。 现在我们可以在应用程序中的任何地方消费 ThemeContext。例如: ``` import React, { useContext } from "react"; import ThemeContext from "./ThemeContext"; function MyComponent() { const theme = useContext(ThemeContext); return ( <div className={`my-component ${theme}`}> { /* 渲染组件内容 */ } </div> ); } export default MyComponent; ``` 在这个例子中,我们使用 useContext 钩子从主题上下文中获取当前主题的值,并将其应用于组件的类名中。 这就是使用 useContext 钩子的基本流程。当然,在实际应用中可能会有更复杂的用法,但是这个示例应该足以让你理解如何使用 useContext 钩子。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值