React中useStarRating钩子点击星星后currentValue始终返回0
React自定义useStarRating钩子状态同步问题解决
问题核心
你的代码存在状态完全脱节的问题:
- Star组件自己维护了独立的
currentValue和hoverValue状态,完全没有使用useStarRating钩子的状态; - AddReviews组件读取的是钩子的状态,两者完全无关,导致父组件永远拿不到Star组件点击后的评分值;
- 钩子中
currentValue初始值为undefined,与Star组件的初始0值不匹配,也会导致显示异常。
解决方案
1. 改造Star组件为受控组件
移除Star组件内部的状态,改为接收外部传入的状态和操作方法:
// Star.js import { faStar } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; const Star = ({ currentValue, hoverValue, handleStarClick, handleStarHover, handleStarLeave }) => { const stars = Array(5).fill(0); return ( <div> <div className="cursor-pointer my-3"> {stars.map((_, index) => { return ( <FontAwesomeIcon key={index} icon={faStar} size="xl" color={(hoverValue || currentValue) > index ? '#FFD700' : '#A9A9A9'} onClick={() => handleStarClick(index + 1)} onMouseOver={() => handleStarHover(index + 1)} onMouseLeave={handleStarLeave} /> ); })} </div> </div> ); }; export default Star;
2. 调整AddReviews组件,传递钩子状态给Star
将useStarRating返回的状态和方法全部传递给Star组件:
// AddReviews.js import Star from './Star'; import useStarRating from '@/hooks/useStarRating'; import axios from 'axios'; import { useState } from 'react'; const AddReviews = () => { const { currentValue, hoverValue, handleStarClick, handleStarHover, handleStarLeave } = useStarRating(); const [reviewText, setReviewText] = useState(''); const handleReviewTextChange = (event) => { setReviewText(event.target.value); }; console.log('currentValue:', currentValue); const handleSubmit = (event) => { event.preventDefault(); axios .post('http://localhost:8080/review/2/user', { rating: currentValue, reviewText: reviewText, }) .then((response) => console.log(response.data)) .catch((error) => console.error(error)); }; return ( <div> <p className="text-xl">Add Review</p> <div> <form className="flex flex-col" onSubmit={handleSubmit}> <Star currentValue={currentValue} hoverValue={hoverValue} handleStarClick={handleStarClick} handleStarHover={handleStarHover} handleStarLeave={handleStarLeave} /> <textarea className="border border-gray-400 rounded-lg p-2" value={reviewText} onChange={handleReviewTextChange} ></textarea> <button className="bg-blue-500 text-white font-bold py-2 px-2 rounded-lg mt-2 "> Post Review </button> </form> </div> </div> ); }; export default AddReviews;
3. 修正useStarRating钩子的初始值和职责
移除不必要的UI导入,将currentValue初始值设为0,保持与显示逻辑一致:
// useStarRating.js import { useState } from 'react'; const useStarRating = () => { const [currentValue, setCurrentValue] = useState(0); const [hoverValue, setHoverValue] = useState(undefined); const handleStarClick = (value) => { setCurrentValue(value); // 注意:setState是异步操作,此处直接打印currentValue会拿到旧值,验证请在组件渲染阶段打印 }; const handleStarHover = (value) => { setHoverValue(value); }; const handleStarLeave = () => { setHoverValue(undefined); }; return { currentValue, hoverValue, handleStarClick, handleStarHover, handleStarLeave, }; }; export default useStarRating;
关键说明
- 受控组件模式:Star组件不再维护内部状态,所有状态由外部钩子控制,确保父组件与子组件状态完全同步;
- 钩子职责单一:钩子只负责状态管理,移除不必要的UI组件导入,符合自定义钩子的设计原则;
- 异步状态更新:
useState的更新是异步的,所以在handleStarClick中直接打印currentValue会拿到旧值,这是React的正常行为,验证状态请在组件渲染阶段(如AddReviews中的console.log)查看。
内容的提问来源于stack exchange,提问作者xAdvitya
相关产品推荐
相关产品推荐

