React - 使用三元在功能组件中应用 CSS class

React - Using ternary to apply CSS class in functional component

我对 React 比较陌生,正在开发 John Conway - Game of Life 应用程序。我为板本身构建了一个 Gameboard.js 功能组件(它是 App.js 的子组件)和一个 Square.js 功能组件,它代表板上的一个单独的正方形(并且是GameboardApp) 的孙子。

App 中,我有一个名为 alive 的函数,我想在用户单击它时更改单个方块的颜色。 App 的状态中还有一个 'alive' 属性 最初设置为 false,alive 将在调用时将 属性 更改为 true。

这是App.js

import React, { Component } from 'react';
import './App.css';
import GameBoard from './GameBoard.js';
import Controls from './Controls.js';

    class App extends Component {
      constructor(props){
        super(props);

        this.state = {
          boardHeight: 50,
          boardWidth: 30,
          iterations: 10,
          reset: false,
          alive: false
        };
      }

      selectBoardSize = (width, height) => {
        this.setState({
          boardHeight: height,
          boardWidth: width
        });
      }

      onReset = () => {

      }

      alive = () => {
        this.setState({ alive: !this.state.alive });
        console.log('Alive function has been called');

      }



      render() {
        return (
          <div className="container">
            <h1>Conway's Game of Life</h1>

          <GameBoard
            height={this.state.boardHeight}
            width={this.state.boardWidth}
            alive={this.alive}
          />

            <Controls
              selectBoardSize={this.selectBoardSize}
              iterations={this.state.iterations}
              onReset={this.onReset}
            />

          </div>
        );
      }
    }

    export default App;

Gameboard 看起来像这样并将 props.alive 传递给 Square:

import React, { Component } from 'react';
import Square from './Square.js';

const GameBoard = (props) => {
    return (
      <div>
        <table className="game-board">
          <tbody>
            {Array(props.height).fill(1).map((el, i) => {
              return (
                <tr key={i}>
                  {Array(props.width).fill(1).map((el, j) => {
                    return (
                      <Square key={j} alive={props.alive}/>
                    );
                  })}
                </tr>
              );
            })}
          </tbody>
         </table>
      </div>
    );
}

export default GameBoard;

在我的 CSS 中,我有一个名为 active 的 class,如果单击它,它会更改单个方块的颜色。我怎样才能在 Square 中单击 td 元素时颜色发生变化(即 CSS classes 变为活动状态)?

我试过这个:

import React, { Component } from 'react';

const Square = (props) => {

  return(
    <td className={props.alive ? "active" : "inactive"} onClick={() => props.alive()}></td>
  );
}

export default Square;

CSS 看起来像这样:

.Square {
  background-color: #013243; //#24252a;
  height: 12px;
  width: 12px;
  border: .1px solid rgba(236, 236, 236, .5);
  overflow: none;

  &:hover {
    background-color: #48dbfb; //#00e640; //#2ecc71; //#39FF14;
  }
}

.inactive {
  background-color: #013243; //#24252a;
}

.active {
  background-color:  #48dbfb;
}

我怎样才能使 .Square CSS class 始终应用于每个方块,但如果它处于活动状态,则单个方块颜色会发生变化?换句话说,我可以将 Square 的 td 设置为始终使用 .Square CSS class 设置样式,然后 Square 中的各个元素可以根据是否适当着色在 App 的状态下 alive 是否为真?

是否有三元方法总是设置一个特定的 CSS class 然后另外设置 2 个中的第一个 classes....即Square CSS class 始终显示,并且根据 logic/state?

呈现活动或非活动状态

你可以这样做

return(
    <td className={`Square ${props.alive ? "active" : "inactive"}`} 
       onClick={() => props.alive()}>
    </td>
  );

请参考这个code

评论有道理

您可以使用 template literal 并在其中嵌入三元条件:

return (
    <td
      className={`Square ${props.alive ? "active" : "inactive"}`}
      onClick={() => props.alive()}
    ></td>
);

快速复习模板文字:使用反引号包裹字符串,您可以通过将其包裹在 ${} 模式中,在其中插入 JavaScript 表达式。作为奖励,模板文字可以跨越多行,因此不再有尴尬的字符串连接!

const myName = "Abraham Lincoln";
const myString = `Some text.
  This text is on the next line but still in the literal.
  Newlines are just fine.
  Hello, my name is ${myName}.`;

编辑:我现在看到的更大问题是您没有在任何地方存储每个单元格的状态。您只有一个布尔值存储在 App 中,称为 alive...您真正需要的是一个 array 布尔值,每个布尔值代表一个状态单身 Square.

"alive" 个状态的数组应该位于 AppGameBoard 中,遵循 "the data flows down" 的 React 原则。在您的情况下,您可以尝试将其保留在 App 中,这样 GameBoardSquare 可以保留纯功能组件。

App 的内部,您可以在构造函数中创建一个新的二维数组 board,并用初始值为 0 的子数组填充它:

// App.js
constructor(props){
    super(props);

    this.state = {
      boardHeight: 50,
      boardWidth: 30,
      board: [],
      iterations: 10,
      reset: false,
    };

    this.state.board = new Array(this.state.boardHeight).fill(new Array(this.state.boardWidth).fill(0));
  }

board数组中,每个索引代表一行。因此 [[0, 0, 1], [0, 1, 0], [1, 1, 1]] 的简化示例将表示:

0 0 1
0 1 0
1 1 1

GameBoard 应该完全基于传递给它的 board 道具渲染你的单元格网格,并将每个 Square 它的活动值和回调函数作为道具传递:

const GameBoard = (props) => {
    return (
      <div>
        <table className="game-board">
          <tbody>
            {this.props.board.map((row, y) => {
              return <tr key={y}>
                {row.map((ea, x) => {
                  return (
                    <Square
                      key={x}
                      x={x}
                      y={y}
                      isAlive={ea}
                      aliveCallback={this.props.alive}
                    />
                  );
                })}
              </tr>;
            })}
          </tbody>
         </table>
      </div>
    );
}

从那里您应该能够看到这个应用程序是如何工作的。 App 存储游戏状态并渲染功能组件 GameBoard。在GameBoard中,每个Square根据其alive值渲染,点击时触发一个aliveCallbackaliveCallback 应该根据其 xy prop.

App 内部的 board 数组中设置适当值的状态

标题问题不是'not working'

的真正原因

注意:此声明

className={props.alive ? "active" : "inactive"}

是正确的,不需要使用模板文字。

您可以通过多种方式write/use:

className={'Square '+ (props.alive ? 'active' : 'inactive')}

事实上,不需要使用 'inactive',因为 'Square' 具有相同的背景颜色。

className={'Square '+ (props.alive ? 'active' : null)}

事实上不需要三元运算符

className={'square '+ (props.alive && 'active')}

当然你可以在 return

之前在纯 js 中 'calculate/prepare' 值
const Square = (props) => {
  let classes = ['Square','bb']
  if( props.alive ) classes.push('active')
  classes = classes.join(' ')
  return (
    <h1 className={classes}>Hello</h1>
  )};

只需阅读 docs 或 google 以获得 'react css in js'。