如何在Reactjs中动态更改已存在元素的类名

huangapple go评论77阅读模式
英文:

How to dynamically change the classname of already existing elements in Reactjs

问题

这是您的代码部分,我将提供翻译的部分:

  1. "I am building a simple memory game and I want to indicate that the player guessed the correct/incorrect answer by modifying the classnames of existing elements such that they flash green or red, I am currently just printing 'CORRECT' and 'WRONG' to the console." 现在我正在构建一个简单的记忆游戏,我想通过修改现有元素的类名来指示玩家是否猜对或猜错答案,目前我只是在控制台上打印'CORRECT'和'WRONG'。

  2. "Here is a function that renders the elements I want to flash green/red:" 这是一个渲染我想要闪烁成绿色/红色的元素的函数:

  3. "And here is the main part of my functional components:" 这是我的功能组件的主要部分:

  4. "I haven't really tried anything yet, I'm just thinking about the problem and coming up with some solutions on how to approach it." 我实际上还没有尝试过什么,我只是在考虑这个问题,并正在思考如何解决它。

  5. "My first idea was to add a parameter to the renderMajorSegment() function which could accept a string based on the correct/wrong answer and then change the classname according to that." 我的第一个想法是向renderMajorSegment()函数添加一个参数,该参数可以根据正确/错误答案接受一个字符串,然后根据该字符串更改类名。

  6. "After some googling, I found that I could store something in state and then modify the class of the elements based on the value of the state. In this case, I would modify the value of the state and I would just be able to reference the state value in the renderSegmentMajor() function and do something similar to what I've already done with the isVisible value." 经过一些搜索,我发现我可以将某些内容存储在状态中,然后根据状态的值修改元素的类。在这种情况下,我将修改状态的值,然后只需能够在renderSegmentMajor()函数中引用状态值,然后执行与我已经对isVisible值所做的类似操作。

  7. "This is my function that will handle the logic and cause the classname changes to occur (when the user submits an answer):" 这是我处理逻辑并导致类名更改发生的函数(当用户提交答案时):

希望这有助于您理解代码和问题的背景。如果您需要更多帮助,请随时提问。

英文:

I am building a simple memory game and I want to indicate that the player guessed the correct/incorrect answer by modifying the classnames of existing elements such that they flash green or red, I am currently just printing 'CORRECT' and 'WRONG' to the console.

Here is a function that renders the elements I want to flash green/red:

  const renderMajorSegment = (musicKey, index) => {
    let arc = calculateArc(outerRadius, innerRadius, musicKey.segmentMetadata.startAngle, musicKey.segmentMetadata.endAngle);
    let [arcCenterX, arcCenterY] = arc.centroid();

    return <g className={`circle-segment ${musicKey.segmentMetadata.majorCircle.isVisible ? 'isVisible': ''}`} 
              key={index}>
            <path 
              d={arc.apply()} // apply() is needed to generate the string that goes into the 'd' attribute
            />
            <text x={arcCenterX} y={arcCenterY} transform={`rotate(15, ${arcCenterX}, ${arcCenterY})`}>
              {abbreviateKeyFromChord(musicKey.chords[0])}
            </text>
          </g>
  }

And here is the main part of my functional components:

  return (
    <div className='circle-of-fifths-container'>
      <svg
        height={diameter*1.1}
        width={diameter*1.1}>
        <g className='circle-container' transform={`translate(${diameter/2 + 25},${diameter/2 + 25}) rotate(-15)`}>
          <circle r={outerRadius} className='base-circle'/>
          <g className='outer-circle-segments-container'>
            {musicKeysObject.map((musicKey, index) => renderMajorSegment(musicKey, index))}
          </g>
          <g className='inner-circle-segments-container'>
            {musicKeysObject.map((musicKey, index) => renderMinorSegment(musicKey, index))}
          </g>
          {mode === READY && 
            <g id='play-button-container' onMouseUp={startRound}>
              <circle r={innerRadius2} id='play-button'/>
              <text id='play-button-text' transform='rotate(15)'>PLAY GAME</text>
            </g>}
        </g>
      </svg>
      {mode === PLAYING &&
        <input placeholder='Your answer' onKeyDown={handleUserInput}></input>
      }
    </div>
  )

I haven't really tried anything yet, I'm just thinking about the problem and coming up with some solutions on how to approach it.

My first idea was to add a parameter to the renderMajorSegment() function which could accept a string based on the correct/wrong answer and then change the classname according to that.

After some googling, I found that I could store something in state and then modify the class of the elements based on the value of the state. In this case, I would modify the value of the state and I would just be able to reference the state value in the renderSegmentMajor() function and do something similar to what I've already done with the isVisible value.

This is my function that will handle the logic and cause the classname changes to occur (when the user submit an answer):

  const handleUserInput = (event) => {
    var index;
    if (hiddenSegment.major) {
      index = 0;
    } else {
      index = 5;
    }

    if (event.key === 'Enter') {
      if (event.target.value === abbreviateKeyFromChord(hiddenSegment.chords[index])) {
        console.log('CORRECT');
        // Set both major and minor circles to true
        // 1 will already be true so it makes no difference, sets the non-visible one to true
        hiddenSegment.segmentMetadata.majorCircle.isVisible = true;
        hiddenSegment.segmentMetadata.minorCircle.isVisible = true;

        // Modify the css classes to make the segments go green

        startRound();
      } else {
        // Modify the css classes to make the segments go red
        console.log('WRONG');
      }
    }
  };

答案1

得分: 0

我正确地认为`useState`是实现我想要的功能的良好方法

这是我的`useState`钩子和我可以用于此钩子的2个值
```javascript
const CORRECT = 'correct';
const WRONG = 'wrong';
const [userAnswer, setUserAnswer] = useState(null);

然后,我可以根据useState的值修改classNames。我正在使用classnames实用工具,使这一点变得更容易并使我的代码更清晰。

var segmentClasses = classNames(
  'circle-segment',
  {'isVisible': musicKey.segmentMetadata.majorCircle.isVisible},
  {'correctAnswer': userAnswer === CORRECT},
  {'wrongAnswer': userAnswer === WRONG}
);

return <g className={segmentClasses} key={index}>
        <path 
          d={arc.apply()} // apply() is needed to generate the string that goes into the 'd' attribute
        />
        <text x={arcCenterX} y={arcCenterY} transform={`rotate(15, ${arcCenterX}, ${arcCenterY})`}>
          {abbreviateKeyFromChord(musicKey.chords[0])}
        </text>
      </g>;

<details>
<summary>英文:</summary>
I was correct in thinking that `useState` was a good method to achieve the functionality I wanted here.
Here is my `useState` hook and the 2 values that I can use for this hook:
```javascript
const CORRECT = &#39;correct&#39;;
const WRONG = &#39;wrong&#39;;
const [userAnswer, setUserAnswer] = useState(null);

I can then modify the classNames based on the value of the useState. I am using the classnames utility to make this a bit easier and make my code cleaner

    var segmentClasses = classNames(
      &#39;circle-segment&#39;,
      {&#39;isVisible&#39;: musicKey.segmentMetadata.majorCircle.isVisible},
      {&#39;correctAnswer&#39;: userAnswer === CORRECT},
      {&#39;wrongAnswer&#39;: userAnswer === WRONG}
    );

    return &lt;g className={segmentClasses} key={index}&gt;
            &lt;path 
              d={arc.apply()} // apply() is needed to generate the string that goes into the &#39;d&#39; attribute
            /&gt;
            &lt;text x={arcCenterX} y={arcCenterY} transform={`rotate(15, ${arcCenterX}, ${arcCenterY})`}&gt;
              {abbreviateKeyFromChord(musicKey.chords[0])}
            &lt;/text&gt;
          &lt;/g&gt;

huangapple
  • 本文由 发表于 2023年5月13日 23:06:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76243416.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定