React.js中如何向动态渲染的列表窗口添加组件
React.js中如何向动态渲染的列表窗口添加组件
嘿,我看了你的代码,问题主要出在数据结构不统一和对react-window渲染逻辑的误解上,咱们一步步理顺解决:
首先你最开始的items是字符串数组,但handleAdd里往list中添加的是{name, id: uuidv4()}这样的对象,这就导致Row组件里artistName={items[index]}(也就是现在的list[index]),新增项时取到的是对象而非字符串,自然渲染不出正确内容。而且你之前尝试直接把RowComponent实例塞进列表的思路也不对——react-window是数据驱动渲染的,我们只需要维护好数据源,组件会自动根据数据生成对应的行,不需要把组件实例存在state里。
下面是修改后的完整代码,我标注了关键改动点:
import React from 'react' import { FixedSizeList } from 'react-window'; import RowComponent from './RowComponent'; import { v4 as uuidv4 } from 'uuid'; // 1. 统一数据结构:初始列表也用对象数组,和后续添加的项结构保持一致 const initialItems = [ { name: "National Anthem", id: uuidv4() } ]; function SongList() { // 2. 用统一结构的initialItems初始化state const [list, setList] = React.useState(initialItems); const [name, setName] = React.useState(''); function handleChange(event){ setName(event.target.value); } function handleAdd(){ if(!name.trim()) return; // 加个空值判断,避免添加空项 // 3. 添加结构一致的对象,用扩展运算符比concat更直观 const newList = [...list, {name, id: uuidv4()}]; setList(newList); setName(''); } return ( <div> <FixedSizeList height={600} width={450} itemSize={75} itemCount={list.length} // 这里会随list长度自动变化,触发列表重新渲染 className="list-container" > {/* 4. 直接在render prop里使用最新的list,避免闭包导致的旧数据问题 */} {({ index, style }) => ( <RowComponent artistName={list[index].name} num={index} style={style} /> )} </FixedSizeList> <div className='adder'> <input type="text" value={name} onChange={handleChange} /> </div> <div className="d-grid gap-2 col-6 mx-auto"> <button className="btn btn-primary m-3" type="button" onClick={handleAdd}>Add Song</button> </div> </div> ); } export default SongList;
再强调几个关键要点:
- 始终保持列表数据源的结构统一,不要混合字符串和对象,否则渲染时会出现类型不匹配的问题
- react-window不需要你把组件实例存在state里,只需要维护好数据,它会根据
itemCount和index自动渲染对应的组件 - 避免把Row组件单独定义在外部(除非你把list作为props传给它),不然会因为闭包捕获旧数据,导致新增项无法正常渲染
这样修改后,你输入歌曲名点击添加按钮,列表就会自动新增对应的RowComponent啦!
备注:内容来源于stack exchange,提问作者AllinTheSauce
相关产品推荐
相关产品推荐

