React函数式组件点击后视图不更新 咨询state更新最佳实践
问题根因
你当前使用普通局部变量stars存储星星状态,React不会监听普通变量的变化,只有通过React状态API更新的状态变化才会触发组件重渲染,因此控制台能看到计算结果,但UI不会同步更新。
问题解答
1、组件内部更新state的最优/推荐方式是什么?
- 函数组件中需要触发UI更新的状态必须通过
useStateHook声明,更新时调用对应的setter函数 - 更新状态必须遵循不可变性原则:不要直接修改原状态(比如直接改数组元素、对象属性),要生成全新的引用值传给setter函数,React才会识别到状态变化
- 如果新状态依赖旧状态的取值,推荐使用函数式更新写法,比如
setCount(prev => prev + 1),可以避免闭包导致的状态旧值问题
2、使用函数式组件时是否必须使用hook?
不是必须。如果你的组件是纯展示组件,仅接收props渲染内容,不需要内部状态、生命周期副作用、上下文等React能力,完全可以不使用任何Hook。
修正后可运行的组件代码
这里提供两种写法,你可以根据需求选择:
写法1:仅存选中索引(更简洁)
import { useState } from 'react'; export default function Rating(props) { // 存储当前选中的星星索引,-1代表未选中 const [selectedIndex, setSelectedIndex] = useState(-1); const emptyStar = '☆'; const filledStar = '★'; function rate(index) { setSelectedIndex(index); } return ( <div className="stars"> {Array.from({ length: props.stars }).map((_, i) => ( <h2 key={i} onClick={() => rate(i)} > {/* 渲染时直接判断当前索引是否在选中范围内 */} {i <= selectedIndex ? filledStar : emptyStar} </h2> ))} </div> ) }
写法2:沿用你原有的存星星数组的逻辑
你之前用useState出错大概率是直接修改了原state的数组,没有传入新的数组引用,调整后如下:
import { useState } from 'react'; export default function Rating(props) { const emptyStar = '☆'; const filledStar = '★'; // 初始化星星数组 const [stars, setStars] = useState(() => Array(props.stars).fill(emptyStar) ); function rate(index) { // 生成全新的数组,不修改原state的数组 const newStars = Array(props.stars).fill(emptyStar); for (let i = 0; i <= index; i++) { newStars[i] = filledStar; } // 传入新数组触发更新 setStars(newStars); } return ( <div className="stars"> {stars.map((star, i) => ( <h2 key={i} onClick={() => rate(i)} > {star} </h2> ))} </div> ) }
内容的提问来源于stack exchange,提问作者London804
相关产品推荐
相关产品推荐

