React Star Widget - 为什么所有星星都在单击时更新?
React Star Widget - why do all stars update on single click?
我正在尝试创建一个星形小部件。我为每颗星星都有一个状态数组,但是当我单击其中一颗星星时,所有星星都将自己设置为该状态。我对此很迷茫,请停下来。我添加了很多调试日志。当我设置 newStars[i] = currentStar;
时,整个 newStars 数组都会更新,但我不明白为什么。
还有,这里是码笔link:https://codepen.io/trismi/pen/zYZpvQq?editors=1111
HTML:
<div id="root">
</div>
CSS(加上很棒的字体样式表 linked in the codepen)
.star {
display: inline-block;
width: 30px;
text-align: center;
color: #ddd;
font-size: 20px;
transform: scale(.8);
transition: transform 50ms ease;
&:hover,
&.semi-active {
color: gold;
transform: scale(1);
}
&.selected {
color: orange;
transform: scale(1);
}
}
JAVASCRIPT
function Star(props) {
console.log(props);
console.log(props.index);
let classes = 'star' + (props.selected ? ' selected' : '') + (props.hover ? ' semi-active' : '');
return (
<div className={classes} onClick={props.onClick}>
<i className="fas fa-star"></i>
</div>
);
}
class RatingWidget extends React.Component {
constructor(props){
super(props);
this.state = {
stars: Array(5).fill({
selected: false,
hover: false,
}),
}
}
handleClick(currentStar, index) {
console.log('\n\n\n******CLICK');
console.log("star state on click", currentStar);
console.log("index", index);
let newStars = this.state.stars.slice();
let newStar = newStars[index];
console.log("new star ", newStar);
newStar.selected = !newStar.selected;
newStars[index] = newStar;
console.log("stars", newStars);
this.setState({
stars: newStars
});
}
render() {
let stars = this.state.stars.map((rating, index) => {
return (
<Star
key={index}
index={index}
onClick={() => this.handleClick(rating, index)}
selected={rating.selected}
hover={rating.hover}
/>);
});
return (
<div className="RatingWidget">
Future rating widget
{stars}
</div>
);
}
}
ReactDOM.render(<RatingWidget />, document.getElementById('root'));
问题出在这里:
Array(5).fill({
selected: false,
hover: false,
})
您正在为数组的每个元素填充相同的对象(相同的引用)。
尝试使用:
Array(5).fill(null).map(() => ({
selected: false,
hover: false,
}))
或使用Array.from():
Array.from({length: 5}, () => ({ selected: false, hover: false}))
您可以拥有以下 handleClick 功能
I updated let newStar = newStars[index]; to let newStar = {...newStars[index]};
handleClick(currentStar, index) {
console.log('\n\n\n******CLICK');
console.log("star state on click", currentStar);
console.log("index", index);
let newStars = this.state.stars.slice();
let newStar = {...newStars[index]};
console.log("new star ", newStar);
newStar.selected = !newStar.selected;
newStars[index] = newStar;
console.log("stars", newStars);
this.setState({
stars: newStars
});
}
我正在尝试创建一个星形小部件。我为每颗星星都有一个状态数组,但是当我单击其中一颗星星时,所有星星都将自己设置为该状态。我对此很迷茫,请停下来。我添加了很多调试日志。当我设置 newStars[i] = currentStar;
时,整个 newStars 数组都会更新,但我不明白为什么。
还有,这里是码笔link:https://codepen.io/trismi/pen/zYZpvQq?editors=1111
HTML:
<div id="root">
</div>
CSS(加上很棒的字体样式表 linked in the codepen)
.star {
display: inline-block;
width: 30px;
text-align: center;
color: #ddd;
font-size: 20px;
transform: scale(.8);
transition: transform 50ms ease;
&:hover,
&.semi-active {
color: gold;
transform: scale(1);
}
&.selected {
color: orange;
transform: scale(1);
}
}
JAVASCRIPT
function Star(props) {
console.log(props);
console.log(props.index);
let classes = 'star' + (props.selected ? ' selected' : '') + (props.hover ? ' semi-active' : '');
return (
<div className={classes} onClick={props.onClick}>
<i className="fas fa-star"></i>
</div>
);
}
class RatingWidget extends React.Component {
constructor(props){
super(props);
this.state = {
stars: Array(5).fill({
selected: false,
hover: false,
}),
}
}
handleClick(currentStar, index) {
console.log('\n\n\n******CLICK');
console.log("star state on click", currentStar);
console.log("index", index);
let newStars = this.state.stars.slice();
let newStar = newStars[index];
console.log("new star ", newStar);
newStar.selected = !newStar.selected;
newStars[index] = newStar;
console.log("stars", newStars);
this.setState({
stars: newStars
});
}
render() {
let stars = this.state.stars.map((rating, index) => {
return (
<Star
key={index}
index={index}
onClick={() => this.handleClick(rating, index)}
selected={rating.selected}
hover={rating.hover}
/>);
});
return (
<div className="RatingWidget">
Future rating widget
{stars}
</div>
);
}
}
ReactDOM.render(<RatingWidget />, document.getElementById('root'));
问题出在这里:
Array(5).fill({
selected: false,
hover: false,
})
您正在为数组的每个元素填充相同的对象(相同的引用)。
尝试使用:
Array(5).fill(null).map(() => ({
selected: false,
hover: false,
}))
或使用Array.from():
Array.from({length: 5}, () => ({ selected: false, hover: false}))
您可以拥有以下 handleClick 功能
I updated let newStar = newStars[index]; to let newStar = {...newStars[index]};
handleClick(currentStar, index) {
console.log('\n\n\n******CLICK');
console.log("star state on click", currentStar);
console.log("index", index);
let newStars = this.state.stars.slice();
let newStar = {...newStars[index]};
console.log("new star ", newStar);
newStar.selected = !newStar.selected;
newStars[index] = newStar;
console.log("stars", newStars);
this.setState({
stars: newStars
});
}