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
    });
  }