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

React解构coinsData实现id全局使用及CoinProvider TS报错求助

问题修复方案

报错核心原因

你遇到的TS报错Type '({ children }: { children?: ReactNode; }) => void' is not assignable to type 'FC<{}>'由以下几个错误共同导致:

  1. 你将CoinContext.Provider的返回逻辑写在了coinsData.map的遍历回调中,整个CoinProvider组件没有合法的顶层返回值,不符合FC类型要求必须返回JSX元素的规则
  2. 初始定义的CoinContext类型为Coin[] | undefined,但实际传入Provider的value是包含分页方法、加载状态等字段的对象,类型完全不匹配
  3. useEffect中写了setTotalPages(totalPages)的无用代码,会触发无限重渲染
    同时你要全局使用id、保留完整coinsData的需求逻辑也存在错误:在map遍历中取到的是每个币种的id,无法直接全局使用,套在map里的Provider会重复渲染多次,逻辑完全不成立。

完整修复代码

import React,{FC, useState, useEffect, ReactNode, createContext, useContext} from 'react'

export interface Coin  {
  id:string;
  name: string;
  current_price: number;
  symbol:string;
  price_change_percentage_24h:number
  image:string;
  market_cap:number
  market_cap_rank:number
}

// 定义Context的准确类型,匹配实际要全局暴露的字段
interface CoinContextType {
  coinsData: Coin[];
  totalPages: number;
  loading: boolean;
  handlePrevPage: () => void;
  handleNextPage: () => void;
  currentPage: number;
  // 全局存储选中的币种id,不需要可以删除
  selectedId: string;
  setSelectedId: (id: string) => void;
}

export const CoinContext = createContext<CoinContextType | undefined>(undefined)

// 封装自定义消费hook,避免每次使用都要判空
export const useCoinContext = () => {
  const context = useContext(CoinContext)
  if (!context) throw new Error('useCoinContext 必须在CoinProvider内部使用')
  return context
}

export const CoinProvider:FC<{children: ReactNode}> = ({children}) => {
  const [loading, setLoading] = useState(false)
  const [page, setPage] = useState(1);
  const [totalPages, setTotalPages] = useState(10);
  const [coinsData, setCoinsData] = useState<Coin[]>([])
  // 全局选中id的状态,不需要可以删除
  const [selectedId, setSelectedId] = useState<string>('')

  const handlePrevPage = () => {
    if (page > 1) setPage(prev => prev - 1);
  };

  const handleNextPage = () => {
    if (page < totalPages) setPage(prev => prev + 1);
  };
        
  useEffect(()=>{
    const fetchData = async () => {
      setLoading(true);
      const response = await fetch(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&page=${page}&per_page=10&sparkline=false`)
      const result = await response.json()
      setCoinsData(result); 
      setLoading(false)
    }
    fetchData()
  },[page])

  // Provider只需要渲染一次,所有全局值直接传入
  return (
    <CoinContext.Provider value={{
      coinsData, 
      totalPages, 
      loading, 
      handlePrevPage, 
      handleNextPage, 
      currentPage: page,
      selectedId,
      setSelectedId
    }}>
      {children}
    </CoinContext.Provider>
  )
}

使用示例

在任意消费Context的组件中,可以直接满足你的需求:

const CoinList = () => {
  const { coinsData, selectedId, setSelectedId } = useCoinContext()
  return (
    <div>
      {/* 遍历完整coinsData渲染列表 */}
      {coinsData.map(coin => (
        <div key={coin.id} onClick={() => setSelectedId(coin.id)}>
          <img src={coin.image} alt={coin.name} width={20}/>
          <span>{coin.name}({coin.symbol.toUpperCase()})</span>
          <span>¥{coin.current_price}</span>
        </div>
      ))}

      {/* 全局使用选中的id */}
      {selectedId && <p>当前选中币种ID:{selectedId}</p>}

      {/* 直接提取所有id数组 */}
      <p>当前页所有币种ID:{coinsData.map(item => item.id).join('、')}</p>
    </div>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 07:15:03