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

React中useReducer结合useContext使用时,页面刷新后子组件state.map内容空白的问题求助

解决刷新页面后产品不渲染的问题

我看了你的代码,发现两个关键问题导致刷新后产品区域空白,点击复选框后又正常:

1. 初始数据加载逻辑错误

在App组件里,你通过fetchInitialBoiler获取初始产品数据,但这个函数是异步的——当useReducer初始化时,fetch请求还没完成,返回的initBoilers是空数组。而之后fetch完成后,你没有通过dispatch更新useReducer的state,所以页面首次渲染时state为空,自然没有产品显示。当你点击复选框时,dispatch了其他动作触发state更新,产品才会正常渲染。

修复方案:
把初始数据的获取放到useEffect里,当fetch完成后,dispatch一个初始化动作来设置state:

修改App组件:

function App () {
  const [count, setCount] = useState(0)
  const [prev, setPrev] = useState([])
  // 先初始化state为空数组
  const [state, dispatch] = useReducer(reducer, [])

  // 用useEffect执行初始数据获取
  useEffect(() => {
    async function loadInitialBoilers() {
      try {
        const response = await fetch('http://localhost:9000/boilers')
        const data = await response.json()
        // dispatch初始化动作
        dispatch({ type: 'INIT', payload: data })
      } catch (err) {
        console.error('加载产品数据失败:', err)
      }
    }
    loadInitialBoilers()
  }, [])

  function reducer (state, action) {
    let current
    switch (action.type) {
      // 添加INIT case来处理初始数据
      case 'INIT':
        return action.payload
      case 'DISPONIBILI':
        current = state.filter(item => item.disponibile) // 简化filter逻辑
        setPrev(current)
        return current
      case 'PROMO':
        current = state.filter(item => item.inSconto)
        setPrev(current)
        return current
      // ...其他case保持不变,记得把所有filter里的三元表达式简化,比如直接写`item.hasOwnProperty('brand') && item.brand === 'Ariston'`
      default:
        return state
    }
  }

  // ...其余代码不变
}

2. React列表key的位置错误

在CardProduct组件的returnCardProduct函数里,你把key={i}放在了内部的<div className="card">元素上,但React要求key必须是map返回的最外层元素的属性。如果key位置不对,React无法正确跟踪列表项的变化,可能导致即使state有数据,也无法正常渲染。

修复方案:
把key移到map返回的最外层<div className="row">上:

function returnCardProduct () {
  return (
    state.map((item, i) => {
      const { brand, descrizione, prezzo, note, stelle } = item
      return (
        // key放在map返回的最外层元素上
        <div className="row" key={i}>
          <div className="colcard">
            <div className="card" style={{ width: 'auto', height: 'auto' }}>
              <Hearty/>
              <img className="card-img-top" src={ boiler } alt="boiler"/>
              <div className="card-body">
                <p className="card-title"> { brand.toUpperCase() }</p>
                <h6 className="card-text">{ descrizione }</h6>
                <Star stelle={ stelle }/>
                <h4> { prezzo } </h4>
                <h5> { note } </h5>
                <Confronta count={ count } setCount={ setCount }/>
              </div>
            </div>
          </div>
        </div>
      )
    }))
}

额外优化建议

  • Filters组件里的计数逻辑有问题,比如{stock.map((item) => item.disponibili )}会把所有disponibili的值拼接成字符串,改成统计数量更合理:{stock.filter(item => item.disponibili).length}
  • reducer里的filter逻辑可以简化,比如item.disponibile ? item : null直接写成item.disponibile,因为filter会自动保留truthy的元素。

做完这些修改后,刷新页面应该就能正常显示产品了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 23:47:38