React卡片点击切换样式后跳转路由选中状态丢失问题咨询
问题根源
你当前的选中状态(勾选状态、背景色、边框样式)都存储在Card组件的内部useState中,路由跳转后组件会重新挂载/渲染,内部状态会重置为初始值,因此选中状态丢失。
解决方案
这里提供两种适配不同场景的实现方案:
方案1:和路由参数绑定(最适配你当前的场景)
你跳转后的路由本身就携带了选中卡片的id,直接从路由读取当前选中id和当前卡片id做对比,就能自动判断激活状态,不需要额外维护状态:
import React from "react"; import { useHistory, useParams } from "react-router"; import styled from "styled-components"; export default function Card(props) { const {item,id} = props; const history = useHistory(); // 直接从动态路由参数取当前激活的id,路由配置为/invoice/:id时可用 const { id: activeId } = useParams(); // 直接判断当前卡片是否激活 const isChecked = activeId === id; // 通过激活状态直接计算样式,不需要单独存state const background = isChecked ? "#fff" : "#F3F1FA"; const cardBorder = isChecked ? "2px solid #7f67ce" : "transparent"; const handleCheck = () => { history.push(`/invoice/${id}`) }; return ( <CardWrapper onClick={handleCheck} background={background} cardBorder={cardBorder} > <div> Content </div> <Check> <input type="checkbox" checked={isChecked} onChange={handleCheck} /> </Check> </CardWrapper> ); } // 样式部分保持原有逻辑即可 const CardWrapper = styled.button` background-color: ${(props) => props.background}; border: ${(props) => props.cardBorder}; display: flex; align-items: center; justify-content: space-between; width: 347px; height: 129px; border-radius: 16px; color: #7f67ce; padding-left: 25px; padding-right: 25px; text-align: left; margin-top:10px; margin-bottom:10px; img { padding-bottom: 15px; } @media(max-width:1200px){ width:300px; } @media(max-width:1200px){ width:280px; } :first-child{ margin-top:0px; } `;
这个方案的优势是完全不需要额外维护状态,刷新页面后选中状态也不会丢失,和路由完全同步。
方案2:状态提升到父组件
如果你需要支持多选、或者不需要和路由绑定的场景,可以把选中状态提到渲染卡片列表的父组件中存储:
- 父组件维护一个
activeId(多选场景可以用activeIdList)状态 - 把
activeId和修改状态的方法通过props传给每个Card组件 - 卡片内部不用存状态,直接通过props传入的
activeId判断是否激活,点击时调用父组件的修改方法更新状态,再跳转路由
这种方式状态存在父组件,只要父组件不卸载,跳转路由回来状态也不会丢失。
原有代码的其他优化点
- 原有input的
onChange={() => CheckBox}没有执行函数,点击复选框本身不会触发状态变更,修复为onChange={handleCheck}即可 - 样式不需要单独存state,可以直接通过激活状态计算得出,减少冗余状态
- 函数名
CheckBox容易和UI组件混淆,建议改为语义化的事件处理函数名比如handleCheck
内容的提问来源于stack exchange,提问作者D.B.J
相关产品推荐
相关产品推荐

