React项目useEffect初始渲染破坏加密货币列表值 该如何解决?
加密货币搜索功能修复方案
问题根因
你的代码存在三个核心问题导致初始渲染无数据:
filter方法的回调箭头函数使用了大括号包裹逻辑但没有显式return,导致所有匹配判断都返回undefined,过滤结果为空- 组件初始化时接口还在请求中,
cryptoList为undefined,useEffect初始执行会将cryptos赋值为undefined - useEffect默认会在组件首次渲染后执行一次,也就是你说的初始化执行问题
最优替代实现方案(无需控制useEffect执行)
筛选结果属于基于cryptoList和searchTerm的派生状态,不需要额外存储为state,也不需要useEffect同步,直接在渲染时计算即可,代码更简洁也不会有初始执行问题:
import { Card, Row, Col, Input } from 'antd' import React from 'react' import { Link } from 'react-router-dom' import { useGetCryptosQuery } from '../services/CryptoApi' import { useState } from 'react' import millify from 'millify' const Cryptocurrencies = (props) => { const count = props.simplified ? 10 : 100; const { data: cryptoList, isFetching } = useGetCryptosQuery(count) const [searchTerm, setSearchTerm] = useState('') if (isFetching) { return "loading..."; } // 直接计算筛选结果,不需要额外state和useEffect const filteredCryptos = cryptoList?.data?.coins?.filter( coin => coin.name.toLowerCase().includes(searchTerm.toLowerCase()) ) || [] return ( <div> <div> <Input placeholder="搜索加密货币" onChange={(e) => setSearchTerm(e.target.value)} /> </div> <Row gutter={[32, 32]} className="crypto-card-container"> {filteredCryptos.map((currency) => ( <Col xs={24} sm={12} lg={6} className="crypto-card" key={currency.id}> <Link to={`/crypto/${currency.id}`}> <Card title={`${currency.rank}.${currency.name}`} extra={<img className="crypto-image" src={currency.iconUrl} />} hoverable > <p>价格 : ${millify(currency.price)}</p> <p>市值 : {millify(currency.marketCap)}</p> <p>日涨跌幅 : {millify(currency.change)}%</p> </Card> </Link> </Col> ))} </Row> </div> ) } export default Cryptocurrencies
禁止useEffect初始执行的实现方法
如果你坚持要使用useEffect实现该功能,可以通过ref标记首次渲染状态,跳过初始执行逻辑:
- 引入
useRef创建首次渲染标记 - 在useEffect首次执行时修改标记,跳过逻辑,后续依赖变化才执行筛选
- 修复原有filter回调的返回值问题
// 新增引入useRef import { useState, useEffect, useRef } from 'react' const Cryptocurrencies = (props) => { const count = props.simplified ? 10 : 100; const { data: cryptoList, isFetching } = useGetCryptosQuery(count) const [cryptos, setCryptos] = useState([]) const [searchTerm, setSearchTerm] = useState('') // 首次渲染标记 const isFirstRender = useRef(true) useEffect(() => { // 接口还在请求中不执行逻辑 if (!cryptoList?.data?.coins) return // 跳过初始渲染执行 if (isFirstRender.current) { isFirstRender.current = false // 初始赋值全量加密货币数据 setCryptos(cryptoList.data.coins) return } // 修复filter回调的返回逻辑,不用大括号可以隐式return const filteredData = cryptoList.data.coins.filter( (coin) => coin.name.toLowerCase().includes(searchTerm.toLowerCase()) ) setCryptos(filteredData) }, [searchTerm, cryptoList]) // 剩下的渲染逻辑和之前一致,用cryptos.map渲染即可 }
内容的提问来源于stack exchange,提问作者Utkrisht Singh
相关产品推荐
相关产品推荐

