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

React中实现按钮点击无刷新切换状态的解决方案

问题描述

我有一组“Yes”“No”按钮,点击后必须刷新页面才会改变颜色。目前用临时方案:在handleClick中添加refresh(),强制每次点击按钮时刷新整个页面。虽然能改变按钮颜色,但希望点击时页面不刷新、不回到顶部,实现按钮颜色无缝切换。

尝试过用e.preventDefault()阻止页面刷新,但因未向处理函数传递事件,不确定当前场景的使用方式。

相关代码如下:

<React.Fragment>
  <Button
    style={{ margin: '0px 5px' }}
    variant="contained"
    onClick={() =>
      handleClick(row.insight_id, row.device_id, 1)
    }
    color={
      row.userConfirmed == null
        ? 'default'
        : row.userConfirmed === 1
        ? 'primary'
        : 'default'
    }
  >
     Yes
  </Button>
   <Button
    style={{ margin: '0px 5px' }}
    variant="contained"
    onClick={() =>
      handleClick(row.insight_id, row.device_id, 0)
    }
    color={
      row.userConfirmed == null
        ? 'default'
        : row.userConfirmed === 1
        ? 'default'
        : 'primary'
    }
  >
    No
  </Button>
</React.Fragment>
const handleClick = (insightId, deviceId, value) => {
    dispatch(updateUserConfirm(insightId, deviceId, value));
    refresh();
};

补充代码:

const userInsightsReducer = (state = initialState, action) => {
  switch (action.type) {
. . . 
case UPDATE_USER_CONFIRM_BEGIN:
      return {
        ...state,
        result: 'BEGINNING',
      };
    case UPDATE_USER_CONFIRM_SUCCESS:
      const userInsightsDataNew = state.userInsightsData
      const insightIndex = state.userInsightsData.findIndex(insight => insight.device_id === action.payload.deviceId && insight.insight_id === action.payload.insightId )
      const updatedInsight = {...state.userInsightsData[insightIndex], userConfirmed:action.payload.value}
      userInsightsDataNew[insightIndex] = updatedInsight
      return {
        ...state,
        userInsightsData : userInsightsDataNew,
        result: "SUCCESS",
      };
    case UPDATE_USER_CONFIRM_FAILURE:
      return {
        ...state,
        result: 'FAILURE',
let row = userInsights.userInsightsData[index];

解决方案

1. 移除强制刷新逻辑

直接删掉handleClick里的refresh()调用——页面刷新完全是手动触发的,只要去掉这行代码,就不会再强制刷新页面。Redux状态更新后会自动触发组件重渲染,根本不需要刷新页面来同步UI。

修改后的handleClick:

const handleClick = (insightId, deviceId, value) => {
    dispatch(updateUserConfirm(insightId, deviceId, value));
};

2. 修复Reducer的状态不可变问题

你的Reducer里直接修改了原数组userInsightsDataNew[insightIndex] = updatedInsight,这违反了Redux状态不可变的原则,会导致Redux检测不到状态变化,组件无法自动重渲染。

需要创建新数组来更新状态:

case UPDATE_USER_CONFIRM_SUCCESS:
  // 对原数组做浅拷贝,生成新数组
  const userInsightsDataNew = [...state.userInsightsData];
  const insightIndex = state.userInsightsData.findIndex(insight => 
    insight.device_id === action.payload.deviceId && insight.insight_id === action.payload.insightId
  );
  
  if (insightIndex !== -1) {
    // 创建新的insight对象替换数组对应位置
    userInsightsDataNew[insightIndex] = {
      ...state.userInsightsData[insightIndex],
      userConfirmed: action.payload.value
    };
  }
  
  return {
    ...state,
    userInsightsData: userInsightsDataNew,
    result: "SUCCESS",
  };

通过[...state.userInsightsData]创建新数组,确保状态引用发生变化,Redux就能感知到更新,触发组件重渲染,按钮颜色自然会同步变化。

3. (可选)简化按钮颜色判断逻辑

可以把颜色判断抽成独立函数,让代码更易读:

const getButtonColor = (userConfirmed, targetValue) => {
  return userConfirmed === null ? 'default' : (userConfirmed === targetValue ? 'primary' : 'default');
};

// 按钮使用示例:
<Button
  style={{ margin: '0px 5px' }}
  variant="contained"
  onClick={() => handleClick(row.insight_id, row.device_id, 1)}
  color={getButtonColor(row.userConfirmed, 1)}
>
  Yes
</Button>

<Button
  style={{ margin: '0px 5px' }}
  variant="contained"
  onClick={() => handleClick(row.insight_id, row.device_id, 0)}
  color={getButtonColor(row.userConfirmed, 0)}
>
  No
</Button>

关于e.preventDefault()的说明

你的场景里页面刷新并非由浏览器默认行为(比如表单提交、链接跳转)触发,而是手动调用refresh()导致的,所以e.preventDefault()完全不适用,去掉refresh()才是根本解决办法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 06:01:45