React Hooks useContext

开发环境是React Native + Taro + Typescript,下面第一部分是父组件

TypeScript 复制代码
import React, { useState } from 'react'
import { View, Text } from '@tarojs/components'
import AppContext, { Theme, User } from './Components/ComContext'
import ContextA from './Components/ContextA'
import ContextB from './Components/ContextB'
import ContextC from './Components/ContextC'
import styles from './index.module.scss'
import {
    HKText,
    HKView
} from 'hk-components';

const UseContext: React.FC = () => {
  const [theme, setTheme] = useState<Theme>(Theme.LIGHT)
  const [user, setUser] = useState<User>({ name: '小明', age: 18 })
  
  const toggleTheme = () => {
    // 使用函数式更新,确保类型安全
    setTheme(currentTheme => 
      currentTheme === Theme.LIGHT ? Theme.DARK : Theme.LIGHT
    )
  }
  
  const updateUser = (newUser: User) => {
    setUser(newUser)
  }
  
  return (
    <AppContext.Provider value={{
      theme,
      toggleTheme,
      user,
      updateUser
    }}>
        {/* 注:如果在这个位置再多写一份AppContext.Provider,那么这个位置的provider的值会覆盖外层的,子组件也会获取覆盖后的值*/}
      <HKView className={styles.container}>
        <Text className='title'>父组件</Text>
        <Text>当前主题: {theme}</Text>
        <Text>用户名: {user.name}</Text>
        <Text>用户年龄: {user.age}</Text>
        
        <View className={styles.showTextBox}>
          <ContextA />
          <ContextB />
        </View>
        <View>
            <Text>在同一个子组件中,实现隔代组件间共享一份数据</Text>
            <ContextC></ContextC>
        </View>
      </HKView>
    </AppContext.Provider>
  )
}

export default UseContext

下面的三部分为子组件:ContextA、ContextB、ContextC

TypeScript 复制代码
import { View, Text, Button } from '@tarojs/components'
import AppContext from './ComContext'
import styles from './index.module.scss'
import {
    HKText,
    HKView
} from 'hk-components';

const ContextA: React.FC = () => {
  const { theme, toggleTheme, user, updateUser } = useContext(AppContext)
  
  const handleIncreaseAge = () => {
    updateUser({ ...user, age: user.age + 1 })
  }
  
  return (
    <HKView className={styles.container}>
        <View className={styles.showTextBox}>
            <Text className={styles.showText}>ContextA 组件</Text>
            <Text className={styles.showText}>当前主题: {theme}</Text>
            <Text className={styles.showText}>用户名: {user.name}</Text>
            <Text className={styles.showText}>用户年龄: {user.age}</Text>
        </View>
        <View className={styles.actionContainer}>
            <Button className={styles.actionBox} onClick={toggleTheme}>切换主题</Button>
            <Button className={styles.actionBox} onClick={handleIncreaseAge}>增加年龄</Button>
        </View>
    </HKView>
  )
}

export default ContextA
TypeScript 复制代码
import React, { useContext } from 'react'
import { View, Text, Button } from '@tarojs/components'
import AppContext from './ComContext'
import styles from  './index.module.scss'
import {
    HKText,
    HKView
} from 'hk-components';

const ContextB: React.FC = () => {
  const { theme, toggleTheme, user, updateUser } = useContext(AppContext)
  
  const handleToggleUser = () => {
    const newName = user.name === '小明' ? '小红' : '小明'
    updateUser({ ...user, name: newName })
  }
  
  return (
    <HKView className={styles.container}>
        <View className={styles.showTextBox}>
            <Text className={styles.showText}>ContextB 组件</Text>
            <Text className={styles.showText}>当前主题: {theme}</Text>
            <Text className={styles.showText}>用户名: {user.name}</Text>
            <Text className={styles.showText}>用户年龄: {user.age}</Text>
        </View>
        <View className={styles.actionContainer}>
            <Button className={styles.actionBox} onClick={toggleTheme}>切换主题</Button>
            <Button className={styles.actionBox} onClick={handleToggleUser}>切换用户</Button>
        </View>
    </HKView>
  )
}

export default ContextB
TypeScript 复制代码
import React, { createContext, useContext, useState } from 'react';
import { View, Text, Button } from '@tarojs/components';
import {
    HKText,
    HKView
} from 'hk-components';

// 创建Context
const MyContext = createContext<any>(null);

// ContextC 父组件
const ContextC: React.FC = () => {
  const [count, setCount] = useState(0);

  const updateCount = (newCount: number) => {
    setCount(newCount);
  };

  const contextValue = {
    message: 'Hello from Context!',
    count,
    updateCount,
    user: {
      name: '张三',
      age: 25
    }
  };

  return (
    <MyContext.Provider value={contextValue}>
      <View style={{ 
        padding: 20, 
        backgroundColor: '#f5f5f5',
        minHeight: '100vh'
      }}>
        <Text style={{ 
          fontSize: 18, 
          fontWeight: 'bold', 
          marginBottom: 16 
        }}>
          ContextC 父组件
        </Text>
        
        <Text style={{ marginBottom: 16 }}>
          当前计数: {count}
        </Text>
        
        <ComXa />
      </View>
    </MyContext.Provider>
  );
};

// ComXa 子组件
const ComXa: React.FC = () => {
  return (
    <View style={{ 
      padding: 16, 
      backgroundColor: '#e3f2fd', 
      margin: 10, 
      borderRadius: 8
    }}>
      <Text style={{ fontSize: 16, marginBottom: 12 }}>
        ComXa 子组件
      </Text>
      <ComXe />
    </View>
  );
};

// ComXe 孙子组件(使用useContext)
const ComXe: React.FC = () => {
  const context = useContext(MyContext);

  if (!context) {
    return (
      <View>
        <Text>Context未找到</Text>
      </View>
    );
  }

  const { message, count, updateCount, user } = context;

  const handleIncrement = () => updateCount(count + 1);
  const handleDecrement = () => updateCount(count - 1);

  return (
    <View style={{ 
      padding: 16, 
      backgroundColor: '#fff3e0', 
      borderRadius: 8
    }}>
      <Text style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 8 }}>
        ComXe 孙子组件
      </Text>
      
      <Text style={{ marginBottom: 8 }}>
        消息: {message}
      </Text>
      
      <Text style={{ marginBottom: 8 }}>
        用户: {user.name} ({user.age}岁)
      </Text>
      
      <Text style={{ marginBottom: 12 }}>
        计数: {count}
      </Text>
      
      <View style={{ flexDirection: 'row', gap: 8 }}>
        <Button onClick={handleDecrement}>
          减少
        </Button>
        <Button onClick={handleIncrement}>
          增加
        </Button>
      </View>
    </View>
  );
};

export default ContextC;

下面为类型推断的一些声明与export

TypeScript 复制代码
import { createContext } from 'react'

// 使用枚举方式定义主题,避免类型推断问题
export enum Theme {
  LIGHT = 'light',
  DARK = 'dark'
}

export interface User {
  name: string
  age: number
}

export interface AppContextValue {
  theme: Theme
  toggleTheme: () => void
  user: User
  updateUser: (user: User) => void
}

// 创建 Context
const AppContext = createContext<AppContextValue>({
  theme: Theme.LIGHT,
  toggleTheme: () => {},
  user: { name: '', age: 0 },
  updateUser: () => {}
})

export default AppContext
相关推荐
SoaringHeart1 小时前
Flutter最佳实践:IM聊天文字链接自动识别跳转
前端·flutter
掘金一周2 小时前
企业中要做智能体,最佳的方案是什么? | 沸点周刊 6.18
前端·人工智能·ai编程
Darling噜啦啦2 小时前
CSS 3D 变换与 Flex 布局实战:从零打造旋转立方体
前端·css
十九画生2 小时前
parentID ``` JavaScript 是区分大小写的,所以这两个不是同一个字段。 第二,`parent` 没有声明。 应该先写: `
javascript
秃头网友小李2 小时前
前端难点:keep-alive 缓存什么?RouterView 的 key 为什么要带 scopeId?
前端·vue.js
鱼人2 小时前
CSS 变量:一个变量救你一百次复制粘贴
前端
长大19882 小时前
CSS 到底是什么?和 HTML 的区别一次讲清楚
前端
禅思院2 小时前
路由性能优化终极指南:从懒加载漏洞到边缘渲染的架构跃迁
前端·架构·前端框架
怕浪猫2 小时前
Electron 开发实战(十六):总结与展望|生态现状、框架对比、行业趋势与学习指南
前端·javascript·electron
文心快码BaiduComate2 小时前
Comate 搭载GLM-5.2:百万上下文,稳定支撑长程任务
前端·程序员·开源