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

React子组件向父组件传递累计重量值及实时渲染问题

问题分析与解决方案

问题背景

现有一个子组件,包含带重量属性的按钮,点击按钮可选择/取消选择对应载荷,所选载荷的重量会进行累加或扣除。需求是将子组件中计算出的累计重量sumCargoValue传递到父组件,并在父组件的计分板中展示。

当前遇到两个问题:

  1. 点击子组件按钮后,父组件的累计重量每两次点击才更新一次,但localStorage中的记录是及时且正确的。
  2. 需要处理长按按钮后的正确渲染问题。

子组件代码

<ul className="lots__list">
 ...
          {filter == "cargo" &&
            lotsSplice.map((item) => (
              <CargoButton
                key={item.id}
                id={item.id}
                weight_value={item.value}
                handleClick={buttonHandler}
                array={lotsSplice}
                card={item}
                ArraySaved={arraySaved}
                isAdded={item.isAdded}
              />
            ))}
        </ul>
function buttonHandler(item, isAdded) {
setLotsSplice(
lotsSplice.map((elem) =>
elem.id === item.id ? { ...elem, isAdded: !elem.isAdded } : elem
));

const tempCargoValue = sumCargoValue;
setSumCargoValue(item.value * 1);

if (isAdded) {
  setSumCargoValue(sumCargoValue * 1 + item.value * 1);
} else {
  setSumCargoValue(sumCargoValue * 1 - item.value * 1);
}

 onBookmarkClick();
}

父组件代码

function CheckWeightCargoFrame({ openPopup }) {
...
  const [sumCargoValue, setsumCargoValue] = useState();
  const [BookmarkClick, setBookmarkClick] = useState("");


  function onBookmarkClick() {
    setBookmarkClick(!setBookmarkClick);
    console.log(localStorage.getItem("selectCargo"));
    setsumCargoValue(localStorage.getItem("selectCargo"));
  }

...

useEffect(() => {
    console.log(localStorage.getItem("selectCargo"));
    setsumCargoValue(localStorage.getItem("selectCargo"));
  } );

 return (
...
        <ListArray
          array={cargo}
          filter="cargo"
          onBookmarkClick={onBookmarkClick}
... 
        />
      )}

      <div className="check-weight__info"> {sumCargoValue}
      </div>
...

问题原因

  1. 子组件状态更新逻辑错误:
    • setSumCargoValue是异步操作,直接使用sumCargoValue计算会获取到旧的状态值。
    • 中间多余的setSumCargoValue(item.value * 1);会覆盖后续的计算结果,导致状态更新混乱。
  2. 父组件回调函数错误:
    • setBookmarkClick(!setBookmarkClick);中误用了状态更新函数setBookmarkClick而非状态值BookmarkClick,导致状态切换逻辑失效。
  3. 依赖localStorage传递状态冗余且不可靠:
    • 用localStorage作为父子组件状态传递的中间层完全没必要,反而会因为localStorage的读写时机与React状态更新不同步,导致显示延迟。
  4. 无依赖的useEffect无限触发:
    • 父组件中的useEffect没有设置依赖项,会在组件每次渲染时都执行,干扰正常的状态更新流程。

解决方案

1. 修正子组件的重量计算逻辑

使用React的函数式状态更新,确保每次计算都基于最新的状态值,同时移除多余的状态更新语句:

function buttonHandler(item, isAdded) {
  // 更新选中状态
  setLotsSplice(prev => 
    prev.map(elem => 
      elem.id === item.id ? { ...elem, isAdded: !elem.isAdded } : elem
    )
  );

  // 正确计算累计重量:基于前一次状态更新
  setSumCargoValue(prevSum => {
    const newValue = Number(item.value);
    return isAdded ? prevSum + newValue : prevSum - newValue;
  });

  // 直接把最新的sumCargoValue传给父组件,不用localStorage
  const newSum = isAdded ? sumCargoValue + Number(item.value) : sumCargoValue - Number(item.value);
  onBookmarkClick(newSum);
}

2. 父组件直接接收子组件传递的重量值

移除冗余的localStorage操作和无依赖的useEffect,修正状态切换逻辑:

function CheckWeightCargoFrame({ openPopup }) {
...
  const [sumCargoValue, setsumCargoValue] = useState(0); // 初始化默认值为0
  const [isBookmarked, setIsBookmarked] = useState(false); // 修正状态命名,更清晰

  // 直接接收子组件传递的最新重量
  function onBookmarkClick(newSum) {
    setIsBookmarked(prev => !prev); // 正确切换状态
    setsumCargoValue(newSum);
  }

  // 移除无依赖的useEffect

 return (
...
        <ListArray
          array={cargo}
          filter="cargo"
          onBookmarkClick={onBookmarkClick}
          initialSum={sumCargoValue} // 把父组件初始值传给子组件
... 
        />
      )}

      <div className="check-weight__info"> {sumCargoValue} kg</div>
...

3. 处理长按按钮的渲染问题

在CargoButton组件中添加长按逻辑,使用useRef记录定时器,区分点击和长按:

function CargoButton({ id, weight_value, handleClick, isAdded }) {
  const longPressTimer = useRef(null);

  // 开始长按计时
  const handleMouseDown = () => {
    longPressTimer.current = setTimeout(() => {
      // 长按逻辑:比如连续累加/扣除,这里根据需求调整
      handleClick({ id, value: weight_value }, !isAdded);
    }, 500); // 长按阈值设为500ms,可自定义
  };

  // 取消长按计时,处理点击逻辑
  const handleMouseUp = () => {
    if (longPressTimer.current) {
      clearTimeout(longPressTimer.current);
      // 普通点击逻辑
      handleClick({ id, value: weight_value }, isAdded);
    }
  };

  // 处理鼠标离开的情况
  const handleMouseLeave = () => {
    if (longPressTimer.current) {
      clearTimeout(longPressTimer.current);
    }
  };

  return (
    <button
      className={`cargo-button ${isAdded ? 'active' : ''}`}
      onMouseDown={handleMouseDown}
      onMouseUp={handleMouseUp}
      onMouseLeave={handleMouseLeave}
      // 兼容移动端触摸事件
      onTouchStart={handleMouseDown}
      onTouchEnd={handleMouseUp}
      onTouchCancel={handleMouseLeave}
    >
      {weight_value} kg
    </button>
  );
}

关键优化点总结

  • 父子组件状态传递直接用回调函数,避免依赖localStorage,保证状态同步。
  • 使用函数式状态更新处理异步状态,确保计算基于最新值。
  • 修正父组件中错误的状态切换逻辑,移除冗余的useEffect。
  • 通过定时器实现长按识别,区分普通点击和长按操作,保证渲染正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 07:35:56