【问题标题】:React - change styling of component onClick and resetReact - 更改组件 onClick 的样式并重置
【发布时间】:2022-10-01 01:39:17
【问题描述】:

所以我正在尝试将宾果游戏实现为一个小型入门反应项目。如果用户得到一个词,那么我希望他们能够单击该框并且样式会更改,以便该框以绿色突出显示,例如。

我目前对这种工作的实现,它改变了框的颜色,但是当我尝试重置并按下“新游戏”时,一些框仍然突出显示并且没有被重置。

我尝试将一个重置道具传递给组件以重置状态,但这并没有奏效,所以我很困惑......

关于我可以做什么的任何想法?

这是我的 app.js

import { useState, useEffect } from \'react\'
import \'./App.css\';
import Cell from \'./components/Cell\';

function App() {
  const [words, setWords] = useState([])
  const [reset, setReset] = useState(false)

  const groupOfWords = [
    { \"word\": \"hello\", id: 1},
    { \"word\": \"react\", id: 2},
    { \"word\": \"gaming\", id: 3},
    { \"word\": \"university\", id: 4},
    { \"word\": \"yoooo\", id: 5},
    { \"word\": \"hockey\", id: 6},
    { \"word\": \"programming\", id: 7},
    { \"word\": \"xbox\", id: 8},
    { \"word\": \"digging\", id: 9},
    { \"word\": \"car\", id: 10}
  ]

  const pickRandomWords = () => {
    setReset(true)

    // Shuffle array
    const shuffled = groupOfWords.sort(() => 0.5 - Math.random())

    // Get sub-array of first n elements after shuffled
    setWords(shuffled.slice(0, 8))
  }

  return (
    <div className=\"App\">
      <h1>Bingo</h1>
      <button onClick={pickRandomWords}>New Game</button>
      <div  className=\'grid\'>
        {words.map(w => (
            <Cell 
              key={w.id}
              word={w.word}
              reset={reset}/>
        ))}
      </div>
    </div>
  );
}

export default App;

这是我的细胞组件

import \'./Cell.css\'
import { useState } from \'react\'

export default function Cell({ word, reset }) {
    const [matched, setMatched] = useState(reset)

    const highlightCell = () => {
        setMatched(true)
    }

    return (
        <div className={matched ? \'cell\' : \'cellMatched\'} onClick={highlightCell}>
            <p>{word}</p>
        </div>
    )
}
  • 当你可以使用setWords([]) 来重置游戏时,为什么你甚至需要这个reset 状态。你的setWords(shuffled.slice(0, 8)) 也应该足够了
  • 所以我之前也有过这样的想法,但是当我开始一个新游戏时 - 网格的单元格会记住它们的状态并保持突出显示
  • 您应该将这个matched 状态向上移动。或者运行useEffect,它将在每次word 更改时清除matched
  • 是的,有趣的是,我想到了第二个选项并尝试了它,但它并没有让我惊讶,但我尝试了与 app.js 匹配的移动

标签: javascript reactjs react-hooks


【解决方案1】:

问题是相同的重置值被传递给元素。您可以在每次重置时传递新值,例如当前时间,并使用useEffect 来捕获该更改。

import React from 'react';
import { useState, useEffect } from 'react'
import './style.css';

export function App(props) {
  const [words, setWords] = useState([])
  const [reset, setReset] = useState(false)

  const groupOfWords = [
    { "word": "hello", id: 1},
    { "word": "react", id: 2},
    { "word": "leidos", id: 3},
    { "word": "university", id: 4},
    { "word": "strathclyde", id: 5},
    { "word": "hockey", id: 6},
    { "word": "programming", id: 7},
    { "word": "xbox", id: 8},
    { "word": "hydrocarbon", id: 9},
    { "word": "car", id: 10}
  ]

  const pickRandomWords = () => {
    setReset(new Date())

    // Shuffle array
    const shuffled = groupOfWords.sort(() => 0.5 - Math.random())

    // Get sub-array of first n elements after shuffled
    setWords(shuffled.slice(0, 8))
  }

  return (
    <div className="App">
      <h1>Bingo</h1>
      <button onClick={pickRandomWords}>New Game</button>
      <div  className='grid'>
        {words.map(w => (
            <Cell 
              key={w.id}
              word={w.word}
              reset={reset}/>
        ))}
      </div>
    </div>
  );
}

function Cell({ word, reset }) {
    const [matched, setMatched] = useState(false)

    const highlightCell = () => {
        setMatched(true)
    }

    useEffect(()=>{

      console.log('reset on', reset)
      setMatched(false)

    },[reset])

    return (
        <div className={matched ? 'cellMatched' : 'cell'} onClick={highlightCell}>
            <p>{word}</p>
        </div>
    )
}

【讨论】:

  • 我更改了您为匹配项目设置类的方式。如果matched 为真,则更有意义,该类应为cellMatched
  • 是的,同上。你的代码就像一个魅力 - 谢谢
  • 是的,当然。不过有人投了反对票!
  • 这不是我的反对意见,但您当前设置了setMatched(false),而不管reset 的值如何。如果 resettrue 更改为 false setMatched(false) 也会被调用。您应该添加一个保护,以便仅在将resetfalse 切换到true 时使用setMatched(false)。例如。 if (!reset) return 这可以防止在从 true 切换到 false 时触发重置。
  • 你是绝对正确的。切换值的默认值或目标也可以作为附加参数传递。如果你想切换。但这只是一个重置。我认为在不必要的时候增加代码的复杂性并不是一个好主意。
【解决方案2】:

您当前的问题是 reset 被用作初始 matched 值:

const [matched, setMatched] = useState(reset)

在第一次渲染Cell 之后更改reset 不会产生任何影响,因为不再使用初始值。

我想为您提供与已经给出的答案不同的答案。让我们首先看一下当前答案的概念,以及您尝试通过在Cell 中拥有reset 属性来实现。

useEffect(() => { setMatched(false) }, [reset]);

这里会发生什么?每当我们完成宾果卡时,我们都会用橡皮擦擦除所有单元格的内容。所以本质上你是在一次又一次地重复使用同一张宾果卡。每次完成游戏后擦除卡片。

与其清除旧卡,不如扔掉它并拿一张新的宾果卡。在 React 中,您可以通过更改其键来强制从头开始创建组件。

这一概念变化也意味着Cell 不需要reset 属性,因为重置游戏时会丢弃一个单元格。

这意味着Cell 定义可能如下所示:

import './Cell.css';
import { useState } from 'react';

export default function Cell({ word }) {
  const [matched, setMatched] = useState(false);

  const highlightCell = () => { setMatched(true) };

  return (
    <div className={matched ? 'cell' : 'cellMatched'} onClick={highlightCell}>
      <p>{word}</p>
    </div>
  );
};

现在我们不能再重置单元格,“游戏”将负责在游戏重置时丢弃旧的Cell 实例。

import { useState, useEffect, useCallback } from 'react';
import './App.css';
import Cell from './components/Cell';

const groupOfWords = [
  { id:  1, word: "hello"       },
  { id:  2, word: "react"       },
  { id:  3, word: "gaming"      },
  { id:  4, word: "university"  },
  { id:  5, word: "yoooo"       },
  { id:  6, word: "hockey"      },
  { id:  7, word: "programming" },
  { id:  8, word: "xbox"        },
  { id:  9, word: "digging"     },
  { id: 10, word: "car"         },
];

function App() {
  const [words,  setWords ] = useState([]);
  const [gameNr, setGameNr] = useState(0);

  const newGame = () => {
    setGameNr(gameNr => gameNr + 1);

    // Shuffle array
    const shuffled = groupOfWords.sort(() => 0.5 - Math.random());

    // Get sub-array of first 8 elements
    setWords(shuffled.slice(0, 8));
  };

  return (
    <div className="App">
      <h1>Bingo</h1>
      <button onClick={newGame}>New Game</button>
      <div  className='grid'>
        {words.map(({id, word}) => (
          <Cell 
            key={JSON.stringify([gameNr, id])}
            word={word}
          />
        ))}
      </div>
    </div>
  );
}

export default App;

在上面的代码中,我将reset 替换为gameNr。这个数字负责丢弃旧细胞。 Cell key 现在是 gameNrid 的组合。因此,如果我们增加gameNr,所有单元格将被赋予一个新的key 值。这反过来将转储所有现有单元并初始化新的Cell 组件。

【讨论】:

    猜你喜欢
    • 2019-10-25
    • 1970-01-01
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 2021-06-16
    • 1970-01-01
    • 2021-08-20
    • 2018-03-09
    相关资源
    最近更新 更多