You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中解构useContext对象:避免重复调用weather.weather及类型错误解决

优化useContext解构写法避免重复调用

我目前使用useContext可正常导入数据,但需重复书写weather.weather才能获取具体值,希望通过解构变量避免重复调用。现有代码运行正常,仅需优化写法。

上下文导出代码

import { createContext, useState, useEffect } from 'react';
import { Weather } from '../../types';
import axios from 'axios';
import { WeatherContextType, WeatherContextProviderProps } from '../../types';

export const WeatherContext = createContext<WeatherContextType | null>(null);

export const WeatherContextProvider = ({ children }: WeatherContextProviderProps) => {
  const [weather, setWeather] = useState<Weather | null>();
  const fetchWeatherData = async () => {
    const response = await axios.get('http://mock-api-call/weather/get-weather');

    setWeather(response.data.result.weather);
  };

  useEffect(() => {
    fetchWeatherData();
  }, []);
  return (
    <WeatherContext.Provider value={{ weather, setWeather }}>{children}</WeatherContext.Provider>
  );
};

数据导入组件代码

import { WeatherContext } from './context/WeatherContext';
import { Title, Text, Container } from '@mantine/core';
import { useContext } from 'react';

const WeatherComponent = () => {
  const weather = useContext(WeatherContext);
  console.log(weather);

  return (
    <Container style={{ width: '100%' }}>
      <Title order={2}>Today's Weather</Title>
      <Text size="lg">
        {weather?.weather?.forcast} with a low of {weather?.weather?.min} and a high of{' '}
        {weather?.weather?.max}
      </Text>
      <Text size="md" data-testid="description">
        {weather?.weather?.description}
      </Text>
    </Container>
  );
};

export default WeatherComponent;

尝试的解构方式及报错

我尝试直接解构:

const {weather} = useContext(WeatherContext);

但出现TypeScript错误:

Property 'weather' does not exist on type 'WeatherContextType | null'.

相关类型定义

export type WeatherContextType = {
  weather: Weather | null | undefined;
  setWeather: React.Dispatch<React.SetStateAction<Weather | null | undefined>>;
};

解决方案

原因分析

报错是因为useContext(WeatherContext)返回的类型是WeatherContextType | null,TypeScript不允许直接解构可能为null的值;同时当前组件里的变量名weather和Context里的weather属性重名,也容易混淆。

方案1:兜底空对象+重命名解构

在解构时先用?? {}处理null的情况,同时重命名Context里的weather属性避免变量名冲突:

const WeatherComponent = () => {
  // 用weatherData重命名Context中的weather属性,同时兜底空对象避免解构null报错
  const { weather: weatherData } = useContext(WeatherContext) ?? {};

  return (
    <Container style={{ width: '100%' }}>
      <Title order={2}>Today's Weather</Title>
      <Text size="lg">
        {weatherData?.forcast} with a low of {weatherData?.min} and a high of{' '}
        {weatherData?.max}
      </Text>
      <Text size="md" data-testid="description">
        {weatherData?.description}
      </Text>
    </Container>
  );
};

方案2:自定义Hook封装(更推荐)

封装一个自定义Hook,确保Context不为null,同时直接返回解构后的可用数据,组件里无需重复处理null:

  1. 在WeatherContext文件中添加自定义Hook:
import { useContext } from 'react';
import { WeatherContext } from './WeatherContext';

export const useWeather = () => {
  const context = useContext(WeatherContext);
  // 如果组件未在Provider内使用,抛出错误提示
  if (!context) {
    throw new Error('useWeather must be used within a WeatherContextProvider');
  }
  return context;
};
  1. 在组件中使用:
import { useWeather } from './context/WeatherContext';
import { Title, Text, Container } from '@mantine/core';

const WeatherComponent = () => {
  // 直接解构Context中的weather属性,此时已确保context不为null
  const { weather } = useWeather();

  return (
    <Container style={{ width: '100%' }}>
      <Title order={2}>Today's Weather</Title>
      <Text size="lg">
        {weather?.forcast} with a low of {weather?.min} and a high of{' '}
        {weather?.max}
      </Text>
      <Text size="md" data-testid="description">
        {weather?.description}
      </Text>
    </Container>
  );
};

方案3:进一步解构Weather对象

如果想彻底避免weather?.xxx的写法,可以在组件里进一步解构Weather对象(注意处理undefined/null):

const WeatherComponent = () => {
  const { weather } = useWeather();
  // 解构Weather对象的属性,兜底空对象避免报错
  const { forcast, min, max, description } = weather ?? {};

  return (
    <Container style={{ width: '100%' }}>
      <Title order={2}>Today's Weather</Title>
      <Text size="lg">
        {forcast} with a low of {min} and a high of {max}
      </Text>
      <Text size="md" data-testid="description">
        {description}
      </Text>
    </Container>
  );
};

内容的提问来源于stack exchange,提问作者meWho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 11:24:24