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

如何将JavaScript物品比较器脚本转化为可正常运行的React应用?

React 物品比较器修复方案

首先,你的代码存在几个核心问题,导致功能异常:

  • 直接修改状态数组:React 状态是不可变的,splice 会直接修改原数组,导致状态更新逻辑混乱
  • 异步状态的 stale 值问题:在事件处理中使用未更新的旧状态值进行判断,导致二分查找的结束条件触发错误
  • 状态依赖未同步:midIndex、primaryItem 等依赖其他状态的值未随状态变化重新计算
  • UI 硬编码渲染:排名列表和按钮文本未动态关联状态,导致数据更新后界面无法同步

以下是修复后的完整代码:

import React, { useState, useEffect } from 'react';

const ItemComparator = () => {
  const initialItems = ['A', 'B', 'C', 'D', 'E'];
  const [rankedList, setRankedList] = useState([initialItems[0]]);
  const [currentItemIndex, setCurrentItemIndex] = useState(1);
  const [left, setLeft] = useState(0);
  const [right, setRight] = useState(0);

  const currentItem = initialItems[currentItemIndex];
  const mid = Math.floor((left + right) / 2);
  const comparisonItem = rankedList[mid];

  // 切换当前处理物品时重置二分查找指针
  useEffect(() => {
    if (currentItemIndex < initialItems.length) {
      setLeft(0);
      setRight(rankedList.length - 1);
    }
  }, [currentItemIndex, rankedList.length]);

  const handlePreference = (preferCurrent) => {
    // 先计算新的指针值,避免异步状态更新的 stale 问题
    let newLeft = left;
    let newRight = right;

    if (preferCurrent) {
      newRight = mid - 1;
    } else {
      newLeft = mid + 1;
    }

    // 更新指针状态
    setLeft(newLeft);
    setRight(newRight);

    // 二分查找结束,插入当前物品到正确位置
    if (newLeft > newRight) {
      const newRankedList = [...rankedList];
      newRankedList.splice(newLeft, 0, currentItem);
      setRankedList(newRankedList);
      // 推进到下一个待处理物品
      setCurrentItemIndex(currentItemIndex + 1);
    }
  };

  const hasMoreItems = currentItemIndex < initialItems.length;

  return (
    <div style={{ maxWidth: '600px', margin: '2rem auto', padding: '0 1rem' }}>
      <h1>物品比较器</h1>
      
      {hasMoreItems ? (
        <>
          <p>你更喜欢哪一个?</p>
          <div style={{ display: 'flex', gap: '1rem', marginBottom: '2rem' }}>
            <button 
              onClick={() => handlePreference(true)}
              style={{ padding: '0.5rem 1rem', fontSize: '1rem' }}
            >
              {currentItem}
            </button>
            <button 
              onClick={() => handlePreference(false)}
              style={{ padding: '0.5rem 1rem', fontSize: '1rem' }}
            >
              {comparisonItem}
            </button>
          </div>
        </>
      ) : (
        <p>✅ 所有物品排序完成!</p>
      )}

      <h2>当前排名</h2>
      <ol>
        {rankedList.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
        {/* 显示未处理的物品,清晰展示进度 */}
        {initialItems.slice(currentItemIndex).map((item, index) => (
          <li key={`unranked-${index}`} style={{ color: '#999' }}>
            {item}(未排序)
          </li>
        ))}
      </ol>
    </div>
  );
};

export default ItemComparator;

关键修复说明:

  1. 不可变状态更新:使用扩展运算符 [...rankedList] 创建新数组,确保 React 能正确检测状态变化并触发重新渲染
  2. 跟踪当前处理项:用 currentItemIndex 替代原逻辑中的循环,每次完成一个物品排序后推进索引,符合 React 事件驱动的逻辑
  3. 同步二分查找指针:通过 useEffect 在切换待处理物品时重置左右指针,保证每次比较从正确的范围开始
  4. 避免 stale 状态值:先计算新的指针值再进行判断,解决异步状态更新导致的逻辑错误
  5. 动态 UI 渲染:用 map 函数动态生成排名列表,同时展示未处理物品,提升用户体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:05:06