这段React代码主要实现了一个电影列表的展示和修改功能,下面分三部分详细解释:
- 状态初始化部分
jsx
复制
const [movies, setMovies] = useState([ {id:1, title: 'spider man', ratings:3}, {id:3, title: 'King Lion', ratings:9}, {id:5, title: 'Super Man', ratings:2}, {id:7, title: 'spider man', ratings:1}, ]);
- 使用
useState
钩子创建状态变量movies
和更新函数setMovies
- 初始值是一个包含4个电影对象的数组
- 每个对象包含三个属性:id(唯一标识)、title(标题)、ratings(评分)
- 事件处理函数(存在问题)
jsx
复制
const handleMovie = () => { setMovies(movies.map(item => item.id === 1 ? {...movies, title:'jon wick'} : item )); }
- 意图:点击按钮时修改id为1的电影标题
- 问题:展开运算符使用错误,应该展开
item
而不是movies
- 正确写法应为:
jsx
复制
{...item, title: 'jon wick'} // 正确写法
- JSX渲染部分(存在问题)
jsx
复制
return ( <section className='custom-bg'> {movies.map(item => ( <li key={Math.random()}>{item.title}</li> ))} <button onClick={handleMovie}>Change Name</button> </section> <section> )
- 问题1:多个根元素(两个
<section>
) - 问题2:列表项缺少父级
<ul>
或<ol>
- 问题3:使用
Math.random()
作为key值(错误做法) - 问题4:最后的
<section>
标签未闭合
需要改进的方面:
- 修正后的handleMovie函数:
jsx
复制
const handleMovie = () => { setMovies(movies.map(item => item.id === 1 ? { ...item, title: 'jon wick' } : item )); }
- 正确的JSX结构:
jsx
复制
return ( <div> <section className='custom-bg'> <ul> {movies.map(item => ( <li key={item.id}>{item.title}</li> // 使用唯一id作为key ))} </ul> <button onClick={handleMovie}>Change Name</button> </section> {/* 第二个section如果有内容需要补充 */} </div> )
最终效果:
- 初始显示4部电影标题
- 点击按钮后,id为1的电影标题会从”spider man”变为”jon wick”
- 其他电影信息保持不变
- 使用正确的key可以保证React的diff算法正常工作
常见问题说明:
- 为什么不能用Math.random()作为key?
- 每次渲染都会生成新key值,导致React无法识别元素
- 会引起不必要的重新渲染
- 可能导致表单状态丢失
- 为什么需要包裹父元素?
- JSX要求根元素必须是单个元素
- 可以用
<div>
或<React.Fragment>
包裹
- 展开运算符(…)的作用:
- 创建对象的浅拷贝
- 保持原有属性不变,只修改指定属性
- 避免直接修改原状态对象