React Hooks useContext

发布于:2025-09-06 ⋅ 阅读:(13) ⋅ 点赞:(0)

开发环境是React Native + Taro + 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

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
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
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

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


网站公告

今日签到

点亮在社区的每一天
去签到