React按钮首次点击列表重复显示问题排查求助
你遇到的首次点击列表重复显示的问题,核心在于全局变量滥用、引用类型状态管理混乱,具体原因如下:
全局变量
list1导致状态污染:
你使用了全局变量list1存储列表项,而数组是引用类型。组件初始化时,data.forEach往list1中填充初始项,useState(list1)让myData与list1指向同一个数组。首次点击按钮后,组件重新渲染,List函数会再次执行data.forEach往list1中push元素,导致myData对应的数组被意外修改,出现重复内容。状态更新方式错误:
按钮点击事件中你写的是setMyData(sortList),这会把sortList函数作为state更新器传给React,但sortList并未使用React传入的prevState参数,而是直接操作全局变量,导致状态更新逻辑混乱。原地修改原始数据:
data.sort()是原地排序方法,会直接修改导入的data数组,导致后续渲染使用的是已排序的数组,进一步加剧状态混乱。组件渲染时重复修改全局变量:
List组件每次渲染都会执行data.forEach((element) => list1.push(...)),全局变量被反复填充,状态完全不可控。
List.js
import "./styles.css"; import React, { useState } from "react"; export default function List({ data }) { // 直接生成初始列表项,无需全局变量 const initialList = data.map(element => ( <li key={element.name}>{`${element.name} ${element.rec_loss} ${element.shap}`}</li> )); const [myData, setMyData] = useState(initialList); const sortList = () => { // 创建数据副本,避免修改原始data数组 const sortedData = [...data].sort((a, b) => { // 合并sort和reverse逻辑,直接实现降序排序 return b.rec_loss - a.rec_loss; }); // 生成排序后的列表项数组 const sortedList = sortedData.map(element => ( <li key={element.name}>{`${element.name} ${element.rec_loss} ${element.shap}`}</li> )); setMyData(sortedList); }; return ( <> <ul>{myData}</ul> <button onClick={sortList}>Sort The list</button> </> ); }
index.js(无需修改)
import { render } from "react-dom"; import { data } from "./data/testdata.js" import App from "./App"; import List from "./List"; const rootElement = document.getElementById("root"); const test = ( <> <App /> <List data={data}/> </> ); render(test, rootElement);
移除全局变量:
完全抛弃全局变量list1,每次生成列表项都创建新数组,彻底避免引用共享导致的意外修改。正确初始化状态:
通过data.map直接生成初始列表项传入useState,状态初始化逻辑清晰且可控。避免修改原始数据:
使用[...data]创建原始数据的浅拷贝,再对副本进行排序,防止污染导入的原始data数组。简化状态更新逻辑:
将排序逻辑整合到组件内部的sortList函数中,直接生成新的列表项数组并调用setMyData更新状态,逻辑直观且符合React状态管理规范。修正按钮绑定:
直接将sortList函数绑定到按钮点击事件,确保点击时直接执行排序并更新状态。
内容的提问来源于stack exchange,提问作者R98

