我正在try 创建一个Quizlet学习类的应用程序,我有多个Card组件的实例.我对它进行了设置,因此当我在其中一张卡片上 Select 答案时,它会根据我 Select 的内容更新状态和显示.底部有换卡按钮.问题是,当我在卡片上 Select 答案时,每个卡片组件的状态都会更新,并且showAnswer被设置为真.我如何防止这种情况发生,并使其只更新同一张卡?

我的卡组件:

export default class Card extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            option_correct: Math.random() > 0.5,
            showAnswer: false,
            optionPicked: 0
        }
    }

    handleClick(optionPicked) {
        console.log(this.state.showAnswer);
        console.log(this.props.prompt + ' 1');
        if (!this.props.hidden) {
            if (!this.state.showAnswer)
                this.setState({
                    optionPicked: optionPicked
                });
            this.setState({
                showAnswer: true
            });
        }
    }

    handleKeyPress(event) {
        console.log(prompt + ' 2');
        if (event.key === 'Enter') {
            this.props.onFinish();
            event.preventDefault();
        }
    }

    render() {

        console.log(this.props.prompt + ' ' + this.state.showAnswer);

        return (
            <div className={`card ${this.state.showAnswer ? "show_answer" : ""}`} onKeyDown={this.handleKeyPress}>
                <div className='prompt'>
                    {this.props.prompt}
                </div>
                <small className={'continue'}>
                    Press Enter to Continue...
                </small>
                <div className='options'>
                    <button className={'option ' +
                        (this.state.option_correct ? 'correct' : 'wrong')
                        + ' ' + (this.state.optionPicked === 1 ? 'picked' : 'not_picked')} onClick={() => {
                        this.handleClick(1);
                    }}>
                        {this.state.option_correct ? this.props.answer : this.props.wrongAnswer}
                    </button>
                    <button className={'option ' + (this.state.option_correct ? 'wrong' : 'correct')
                        + ' ' + (this.state.optionPicked === 2 ? 'picked' : 'not_picked')} onClick={() => {
                        this.handleClick(2);
                    }}>
                        {this.state.option_correct ? this.props.wrongAnswer : this.props.answer}
                    </button>
                </div>
            </div>
        );
    }
}

我的卡容器组件:

class CardData {
    constructor(prompt, answer, wrongAnswer) {
        this.prompt = prompt;
        this.answer = answer;
        this.wrongAnswer = wrongAnswer;
    }
}

export default function Cards() {
    const [flashcarddata, setFlashcarddata] = useState([]);
    const [current, setCurrent] = useState(0);

    useEffect(() => {
        setFlashcarddata([
            new CardData('word1', 'correct', 'incorrect'),
            new CardData('word2', 'correct 2', 'incorrect 2'),
            new CardData('word3', 'correct 23', 'incorrect 23')
        ])
    }, []);

    const cards = flashcarddata.map((card, index) => {
        return <Card
            prompt={card.prompt}
            answer={card.answer}
            wrongAnswer={card.wrongAnswer}
            hidden={current !== index}
            onFinish={() => {
                console.log('finished ' + card.prompt);
                nextCard();
            }}
        />;
    });

    function previousCard() {
        setCurrent(current - 1);
    }
    function nextCard() {
        setCurrent(current + 1);
    }

    const loading = <div className="loading">Loading card...</div>;

    return (
        <div>
            {flashcarddata && flashcarddata.length > 0 ? cards[current] : loading}

            <div className="nav">
                {current > 0 ? (
                    <button onClick={previousCard}>Previous card</button>
                ) : (
                    <button className="disabled" disabled>
                        Previous card
                    </button>
                )}
                {current < flashcarddata.length - 1 ? (
                    <button onClick={nextCard}>Next card</button>
                ) : (
                    <button className="disabled" disabled>
                        Next card
                    </button>
                )}
            </div>
        </div>
    );
}

到目前为止,我已经try 将Card从函数组件更改为一个类,使handleClick方法仅在卡是正在显示的那张卡的情况下工作,并从呈现每一张卡并将其中大多数在CSS中设置为display: block改为一次只呈现一张卡.

推荐答案

当您更新一个Card组件的状态时,它会更新所有Card个组件的状态,因为它们都具有相同的初始状态.

解决此问题的一种方法是将状态从Card组件移到父Cards组件中.然后,您可以将当前卡片的状态作为props 传递给每个Card组件,并在单击卡时更新Cards组件中的状态.

下面是一个如何做到这一点的例子:

class CardData {
  constructor(prompt, answer, wrongAnswer) {
    this.prompt = prompt;
    this.answer = answer;
    this.wrongAnswer = wrongAnswer;
  }
}

function Cards() {
  const [flashcarddata, setFlashcarddata] = useState([]);
  const [current, setCurrent] = useState(0);
  const [currentCardState, setCurrentCardState] = useState({
    option_correct: Math.random() > 0.5,
    showAnswer: false,
    optionPicked: 0
  });

  useEffect(() => {
    setFlashcarddata([
      new CardData('word1', 'correct', 'incorrect'),
      new CardData('word2', 'correct 2', 'incorrect 2'),
      new CardData('word3', 'correct 23', 'incorrect 23')
    ]);
  }, []);

  const cards = flashcarddata.map((card, index) => {
    return (
      <Card
        prompt={card.prompt}
        answer={card.answer}
        wrongAnswer={card.wrongAnswer}
        hidden={current !== index}
        showAnswer={currentCardState.showAnswer}
        optionPicked={currentCardState.optionPicked}
        option_correct={currentCardState.option_correct}
        onFinish={() => {
          console.log('finished ' + card.prompt);
          nextCard();
        }}
        onClick={() => {
          setCurrentCardState({
            ...currentCardState,
            optionPicked: optionPicked,
            showAnswer: true
          });
        }}
      />
    );
  });

  function previousCard() {
    setCurrent(current - 1);
  }
  function nextCard() {
    setCurrent(current + 1);
  }

  const loading = (
    <div className="loading">Loading card...</div>
  );

  return (
    <div>
      {cards}
      <button onClick={previousCard}>Previous</button>
      <button onClick={nextCard}>Next</button>
    </div>
  );
}

在上面的代码中,Card个组件的状态由父Cards组件管理,Card个组件基于当前卡的状态呈现.当单击卡时,更新Cards组件中的状态,并将新状态作为props 向下传递给Card个组件.这确保每个Card个组件都有其自己的状态,并且独立于其他Card个组件进行更新.

Javascript相关问答推荐

. NET中Unix时间转换为日期时间的奇怪行为

按下同意按钮与 puppeteer 师

微软Edge编辑和重新发送未显示""

当使用';字母而不是与';var#39;一起使用时,访问窗口为什么返回未定义的?

是什么导致了这种奇怪的水平间距错误(?)当通过JavaScript将列表项元素追加到无序列表时,是否在按钮之间?

在使用REACT更改了CSS类之后,无法更改CSS样式

触发异步函数后不能显示数据

警告框不显示包含HTML输入字段的总和

Docent.cloneNode(TRUE)不克隆用户输入

如何使用Astro优化大图像?

构建器模式与参数对象输入

重新呈现-react -筛选数据过多

如何在尚未创建的鼠标悬停事件上访问和着色div?

是否设置以JavaScript为背景的画布元素?

TypeORM QueryBuilder限制联接到一条记录

在范围数组中查找公共(包含)范围

JSX/React -如何在组件props 中循环遍历数组

Rails 7:在不使用导入映射的情况下导入Java脚本

在Reaction Native中,ScrolltoIndex在结束时不一致地返回到索引0

Js问题:有没有办法将数据从标记表转换成图表?