这段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>包裹
- 展开运算符(…)的作用:
- 创建对象的浅拷贝
- 保持原有属性不变,只修改指定属性
- 避免直接修改原状态对象