React入门之Context-API的使用案例

Posted 安之ccy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React入门之Context-API的使用案例相关的知识,希望对你有一定的参考价值。

前言

上文我们说到,可以使用redux来管理数据,这篇文章则使用Context来管理数据

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言

Context使用顶层共享组件来存储和提供数据,该组件嵌套的子组件均可以使用与更新共享组件的数据,因此子组件也被称为消费组件

Context 主要应用场景在于很多不同层级的组件需要访问同样一些的数据。请谨慎使用,因为这会使得组件的复用性变差

基本搭建

新建Navbar和SongList组件,添加相应样式,然后在App.js中使用,效果是这样的:



创建Context

  1. 创建Context对象,定义一个浅色 vs 深色主题的样式,作用到Navbar和SongList组件上
  2. 取isLightTheme为标识,当值为true时,代表子组件选择使用浅色主题;
  3. 当值为false时,代表子组件选择使用深色主题
import React,  Component, createContext  from 'react';
// 创建context对象
export const ThemeContext = createContext();
// 数据定义
class ThemeContextProvider extends Component 
    state = 
        isLightTheme:true,
        light:
            ui:'#ddd',
            font:'#555',
            bg:'#eee'
        ,
        dark:
            ui:'#333',
            font:'#ddd',
            bg:'#555'
        
    

    render()
    	// 返回一个 Provider React 组件,它允许消费组件订阅 context 的变化
    	// 将数据传递给子组件
        return (
            <ThemeContext.Provider value=...this.state>
                this.props.children
            </ThemeContext.Provider>
        )
    

export default ThemeContextProvider;

在App.js中引入ThemeContextProveder组件;
包裹住需要设置主题的组件:Navbar和SongList

import Navbar from "./components/Navbar";
import SongList from "./components/SongList";
import ThemeContextProvider from "./contexts/ThemeContext";

function App() 
  return (
    <div className="App">
      <ThemeContextProvider>
        <Navbar />
        <SongList />
      </ThemeContextProvider>
      
    </div>
  );


export default App;

这样我们就能在Navbar和SongList里使用共享的数据了

获取数据的方式有两种,一种是通过contextType获取,另一种是通过consumer获取


使用contextType获得数据

Navbar.js

import React,  Component  from 'react'
import  ThemeContext  from '../contexts/ThemeContext';

class Navbar extends Component 
    static contextType = ThemeContext; // 使用contextType获取共享的数据

    render() 
        const  isLightTheme, light, dark  = this.context; // 解构变量
        const theme = isLightTheme ? light : dark; // 当isLightTheme为true时,用浅色主题
        // 返回带有主题样式的JSX模板内容
        return (
            <nav style=background:theme.bg, color:theme.font>
                <h1>Context App</h1>
                <ul>
                    <li>Home</li>
                    <li>About</li>
                    <li>Contact</li>
                </ul>
            </nav>
        )
    


export default Navbar;

效果:浅色主题的导航栏



SongList.js
import React, Component from 'react'
import  ThemeContext  from '../contexts/ThemeContext';

class SongList extends Component 
    static contextType = ThemeContext;
    render()
        const  isLightTheme, light, dark  = this.context;
        const theme = isLightTheme ? light : dark;
        return (
            <div className='song-list' style=background:theme.bg, color:theme.font> 
                <ul>
                    <li style=background:theme.ui>大鱼</li>
                    <li style=background:theme.ui>幽灵公主</li>
                    <li style=background:theme.ui></li>
                </ul>
            </div>
        )
    


export default SongList;

效果:浅色主题的导航栏和主体部分



使用consumer获取共享数据

Navbar.js

import React,  Component  from 'react'
import  ThemeContext  from '../contexts/ThemeContext';

class Navbar extends Component 

    render() 
		// 调用Consumer方法,其child只能有一个,且为function
        return (
            <ThemeContext.Consumer>
                
                    (context) => 
                        const  isLightTheme, light, dark  = context;
                        const theme = isLightTheme ? light : dark;
                        return (
                            <nav style= background: theme.bg, color: theme.font >
                                <h1>Context App</h1>
                                <ul>
                                    <li>Home</li>
                                    <li>About</li>
                                    <li>Contact</li>
                                </ul>
                            </nav>
                        )
                    
                

            </ThemeContext.Consumer>
        )
    


export default Navbar;

SongList.js

import React,  Component  from 'react'
import  ThemeContext  from '../contexts/ThemeContext';

class SongList extends Component 
    render() 

        return (
            <ThemeContext.Consumer>
                
                    (context) => 
                        const  isLightTheme, light, dark  = context;
                        const theme = isLightTheme ? light : dark;
                        return (
                            <div className='song-list' style= background: theme.bg, color: theme.font >
                                <ul>
                                    <li style= background: theme.ui >大鱼</li>
                                    <li style= background: theme.ui >幽灵公主</li>
                                    <li style= background: theme.ui ></li>
                                </ul>
                            </div>
                        )
                    
                
            </ThemeContext.Consumer>

        )
    


export default SongList;

效果同上


更新共享数据

  • 数据是存储在ThemeContext里的,props也可以传递函数,
  • 因此,我们可以在ThemeContext里定义更新数据的函数,并传递给消费组件,
  • 消费组件返回要更新的信号,ThemeContext就开始更新
    // 更换主题
    toggleTheme = () => 
        this.setState(
            isLightTheme: !this.state.isLightTheme
        )
    
	// 在原来传递state数据的基础上,加上更换主题的函数
    render() 
        return (
            <ThemeContext.Provider value= ...this.state, toggleTheme: this.toggleTheme >
                this.props.children
            </ThemeContext.Provider>
        )
    

SongList组件接收该函数并给出回应
增加一个”切换主题“的按钮,点击一下就调用toggleTheme,切换主题样式

<ThemeContext.Consumer>
    
        (context) => 
            const  isLightTheme, light, dark, toggleTheme  = context; // 添加“切换主题”函数的解构
            const theme = isLightTheme ? light : dark;
            return (
                <div className='song-list' style= background: theme.bg, color: theme.font >
                    <ul>
                        <li style= background: theme.ui >大鱼</li>
                        <li style= background: theme.ui >幽灵公主</li>
                        <li style= background: theme.ui ></li>
                    </ul>
                    <button onClick=toggleTheme>切换主题</button>
                    /* 点击按钮时触发toggleTheme函数 */
                </div>
            )
        
    
</ThemeContext.Consumer>

效果:


创建多个context

首先是创建新的context,功能比较简单,就是打招呼,hello~

  • 定义了一个布尔变量isAGirl,默认为true
  • 定义一个问候语的切换函数toggleGreeting
  • 把state和函数都传递给消费组件
import React,  Component, createContext  from 'react';

export const GreetingContext = createContext();

class GreetingContextProvider extends Component 
    state = 
        isAGirl: true
    
    // 更换问候语
    toggleGreeting = () => 
        this.setState(
            isAGirl: !this.state.isAGirl
        )
    

    render() 
        return (
            <GreetingContext.Provider value= ...this.state, toggleGreeting: this.toggleGreeting >
                this.props.children
            </GreetingContext.Provider>
        )
    

export default GreetingContextProvider;

然后是在App.js中引入,用GreetingContextProvider包裹消费组件(其他库和包的引入省略)

import GreetingContextProvider from "./contexts/GreetingContext";

function App() 
  return (
    <div className="App">
      <GreetingContextProvider>
        <ThemeContextProvider>
          <Navbar />
          <SongList />
        </ThemeContextProvider>
      </GreetingContextProvider>
    </div>
  );

最后是在Navbar组件中使用

使用contextType和consumer的区别之一是:

  • contextType只能接收一个context的数据,且是距离该消费组件最近的context
  • consumer可以接收多个context的数据

因此,创建多个context的案例,我们用consumer来获取多个context的数据

render() 

    return (
    // 使用GreetingContext.Consumer再包裹一层,解构该context中的数据和函数
    // 当isAGirl为true时,显示'hello,girl~',否则显示'hello,boy~'
    // 点击该文本,切换问候语
        <GreetingContext.Consumer>
            
                (greetingContext) => 
                    const  isAGirl, toggleGreeting  = greetingContext;
                    return (
                        <ThemeContext.Consumer>
                            
                                (themeContext) => 
                                    const  isLightTheme, light, dark  = themeContext;
                                    const theme = isLightTheme ? light : dark;
                                    return (
                                        <nav style= background: theme.bg, color: theme.font >
                                            <h1>Context App</h1>
                                            <div onClick=toggleGreeting>
                                                 isAGirl ? 'hello,girl~' : 'hello,boy~'
                                            </div>
                                            <ul>
                                                <li>Home</li>
                                                <li>About</li>
                                                <li>Contact</li>
                                            </ul>
                                        </nav>
                                    )
                                
                            

                        </ThemeContext.Consumer>
                    )

                
            
        </GreetingContext.Consumer>

    )

总体效果:


以上是关于React入门之Context-API的使用案例的主要内容,如果未能解决你的问题,请参考以下文章

使用 Axios 等 HTTP 客户端在 context-api 状态下存储获取的数据是一个好习惯吗?

React入门之ReactHooks基本使用

React入门之ReactHooks基本使用

React入门之Redux:react-redux基本使用

React入门之Redux:react-redux基本使用

mobx 知识点集合案例(快速入门)