React - Использование тернар для применения CSS-класса в функциональном компоненте - PullRequest
0 голосов
/ 19 сентября 2018

Я относительно новичок в React и работаю над приложением John Conway - Game of Life.Я построил функциональный компонент Gameboard.js для самой платы (который является дочерним элементом App.js) и функциональный компонент Square.js, который представляет отдельный квадрат на доске (и является дочерним элементом Gameboard и внукомиз App).

В 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, который меняет цвет отдельного квадрата, если на него нажать.Как сделать так, чтобы в Square при нажатии на элемент td цвет менялся (т. Е. CSS-классы менялись на активные)?

Я пробовал это:

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

Как я могу сделать так, чтобы CSS-класс .Square ВСЕГДА применялся к каждому квадрату, но цвет отдельного квадрата изменяется, если он активен?Другими словами, можно ли установить Square 'td, чтобы он всегда стилизовался с помощью CSS-класса .Square, и тогда отдельные элементы в Square могут быть соответствующим образом окрашены в зависимости от того, истинно ли alive в App'Состояние s?

Существует ли троичный подход, чтобы всегда устанавливать один конкретный класс CSS, а затем, кроме того, устанавливать 1 из 2 других классов .... т.е. класс Square CSS всегда отображается, а активным или неактивным являетсяотображается в зависимости от логики / состояния?

Ответы [ 3 ]

0 голосов
/ 19 сентября 2018

Комментарии имеют правильную идею.

Вы можете использовать шаблонный литерал и встраивать троичные условные выражения так:

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

Быстрое обновление литералов шаблона: используйте backticks для переноса строки, и вы можете вставить в нее выражение 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 ... что вам действительно нужно, это массив логических значений, причем каждый логический тип представляет состояние одного Square.

Массив «живых» состояний должен находиться в App или GameBoard, следуя принципу React «данные стекают» .В вашем случае вы можете попытаться сохранить его в App, и тогда GameBoard и Square могут остаться чисто функциональными компонентами.

Внутри App вы можете создать новый 2-мерный массив,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 сохраняет состояние игры и отображает функциональный компонент GameBoardGameBoard каждый Square рендерится в соответствии со своим живым значением и при нажатии запускает aliveCallback.aliveCallback должен установить состояние соответствующего значения в массиве board внутри App, основываясь на его x и y prop.

0 голосов
/ 22 сентября 2018

Проблема из названия не была реальной причиной 'не работает'

ПРИМЕЧАНИЕ. Это утверждение

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

правильно , использование литералов шаблона не требуется.

Вы можете написать / использовать его многими способами:

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

Чтобы быть правдой, нет необходимости использовать «неактивный», поскольку «Квадрат» имеет тот же цвет bg.

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

и де-факто нет необходимости в троичном операторе

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

и, конечно, вы можете «вычислить / подготовить» значения в простых js перед возвратом

const Square = (props) => {
  let classes = ['Square','bb']
  if( props.alive ) classes.push('active')
  classes = classes.join(' ')
  return (
    <h1 className={classes}>Hello</h1>
  )};

Просто прочитайте docs или Google для 'реагировать на cssв js '.

0 голосов
/ 19 сентября 2018

Вы можете сделать как

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

Пожалуйста, укажите этот код

...