Aula 02 - React - Passando dados por props

Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no Facebook

Esse é o link do código fluente no Pinterest

Meus links de afiliados:

Hostinger

Digital Ocean

One.com

Melhore seu NETWORKING

Participe de comunidades de desenvolvedores:

Fiquem a vontade para me adicionar ao linkedin.

E também para me seguir no GITHUB.

Ah, se puder, clica na estrela nos meus repositórios pra dá uma força ao meu perfil no GITHUB

Código da branch inicial:

https://github.com/toticavalcanti/tutorial-react/tree/tic_tac_toe

Link da documentação oficial:

https://reactjs.org/tutorial/

Passando dados por props

No método renderSquare do Board, altere o código para passar o props chamado value para o Square: src/index.js

class Square extends React.Component {
  render() {
    return (
      <button className="square">
        {this.props.value}
      </button>
    )
  }
}
class Board extends React.Component {
  renderSquare(i) {
      return <Square value={i} />;
    }
  render() {
    const status = 'Next player: X';
    return (
      React.createElement("div", null,
      React.createElement("div", { className: "status" }, status),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(0),
      this.renderSquare(1),
      this.renderSquare(2)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(3),
      this.renderSquare(4),
      this.renderSquare(5)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(6),
      this.renderSquare(7),
      this.renderSquare(8))));
  }
}
class Game extends React.Component {
  render() {
    return (
      React.createElement("div", { className: "game" },
      React.createElement("div", { className: "game-board" },
      React.createElement(Board, null)),

      React.createElement("div", { className: "game-info" },
      React.createElement("div", null),
      React.createElement("ol", null))));
  }
}
// ========================================
ReactDOM.render(
React.createElement(Game, null),
document.getElementById('root'));
Passamos um “props” do componente Board, que é o pai, para um componente filho, o Square.

Preenchendo o componente Square com um “X” quando clicamos nele:

src/index.js

class Square extends React.Component {
  render() {
    return (
      <button className="square" onClick={function() { alert('click'); }}>
        {this.props.value}
      </button>
    )
}
class Board extends React.Component {
  renderSquare(i) {    
    return <Square value={i} />;
}
  render() 
    const status = 'Next player: X';
    return (
      React.createElement("div", null,
      React.createElement("div", { className: "status" }, status),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(0),
      this.renderSquare(1),
      this.renderSquare(2)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(3),
      this.renderSquare(4),
      this.renderSquare(5)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(6),
      this.renderSquare(7),
      this.renderSquare(8))));
  }
}
class Game extends React.Component {
  render() {
    return (
      React.createElement("div", { className: "game" },
      React.createElement("div", { className: "game-board" },
      React.createElement(Board, null)),

      React.createElement("div", { className: "game-info" },
      React.createElement("div", null),
      React.createElement("ol", null))));
  }
}
// ========================================
ReactDOM.render(
React.createElement(Game, null),
document.getElementById('root'));

Clicando em um quadrado aparecerá um alerta no seu navegador.

Refatorando a onClick para usar arrow function. src/index.js

class Square extends React.Component {
  render() {
    return (
      <button className="square" onClick={ () => this.setState({value: 'X'}) }>
        {this.props.value}
      </button>
    )
}
class Board extends React.Component {
  renderSquare(i) {    
    return <Square value={i} />;
}
  render() 
    const status = 'Next player: X';
    return (
      React.createElement("div", null,
      React.createElement("div", { className: "status" }, status),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(0),
      this.renderSquare(1),
      this.renderSquare(2)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(3),
      this.renderSquare(4),
      this.renderSquare(5)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(6),
      this.renderSquare(7),
      this.renderSquare(8))));
  }
}
class Game extends React.Component {
  render() {
    return (
      React.createElement("div", { className: "game" },
      React.createElement("div", { className: "game-board" },
      React.createElement(Board, null)),

      React.createElement("div", { className: "game-info" },
      React.createElement("div", null),
      React.createElement("ol", null))));
  }
}
// ========================================
ReactDOM.render(
React.createElement(Game, null),
document.getElementById('root'));
O próximo passo, é fazer o componente Square lembrar que foi clicado e preencher com um “X”. Para guardar o estado de clicado, usaremos o estado(state) do componente square. Os componentes React podem ter estados, configurando o this.state em seus construtores. O this.state deve ser considerado como privado para o componente React que o definiu. Vamos armazenar o valor atual do Square em this.state e alterá-lo quando o Square for clicado. Primeiro, adicionaremos um construtor à classe para inicializar o estado. Todos os componentes de classe React que possuem um método constructor, devem iniciá-lo com uma chamada super(props). src/index.js

class Square extends React.Component {
  constructor(props) {
      super(props);
      this.state = {
        value: null,
    };
  }
  render() {
    return (
      <button className="square" onClick={ () => this.setState({value: 'X'}) }>
        {this.props.value}
      </button>
    )
}
class Board extends React.Component {
  renderSquare(i) {    
    return <Square value={i} />;
}
  render() 
    const status = 'Next player: X';
    return (
      React.createElement("div", null,
      React.createElement("div", { className: "status" }, status),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(0),
      this.renderSquare(1),
      this.renderSquare(2)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(3),
      this.renderSquare(4),
      this.renderSquare(5)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(6),
      this.renderSquare(7),
      this.renderSquare(8))));
  }
}
class Game extends React.Component {
  render() {
    return (
      React.createElement("div", { className: "game" },
      React.createElement("div", { className: "game-board" },
      React.createElement(Board, null)),

      React.createElement("div", { className: "game-info" },
      React.createElement("div", null),
      React.createElement("ol", null))));
  }
}
// ========================================
ReactDOM.render(
React.createElement(Game, null),
document.getElementById('root'));
Agora vamos mudar o método render do componente Square para exibir o valor do estado (state) atual quando clicado:
  • Substitua this.props.value por this.state.value dentro da tag <button>.
  • Coloque props className e onClick em linhas separadas para melhor legibilidade.
Então vamos fazer a modificação e a reidentação. src/index.js

class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null,
    };
  }
  render() {
    return (
      <button
        className="square"
        onClick={() => this.setState({value: 'X'})}
      >
        {this.state.value}
      </button>
    );
  }
}
class Board extends React.Component {
  renderSquare(i) {    
    return <Square value={i} />;
}
  render() 
    const status = 'Next player: X';
    return (
      React.createElement("div", null,
      React.createElement("div", { className: "status" }, status),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(0),
      this.renderSquare(1),
      this.renderSquare(2)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(3),
      this.renderSquare(4),
      this.renderSquare(5)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(6),
      this.renderSquare(7),
      this.renderSquare(8))));
  }
}
class Game extends React.Component {
  render() {
    return (
      React.createElement("div", { className: "game" },
      React.createElement("div", { className: "game-board" },
      React.createElement(Board, null)),
      React.createElement("div", { className: "game-info" },
      React.createElement("div", null),
      React.createElement("ol", null))));
  }
}
// ========================================
ReactDOM.render(
React.createElement(Game, null),
document.getElementById('root'));

Completando o jogo

Para completar o jogo, precisamos preencher os “X”s e os “O”s no tabuleiro(Board) e de alguma maneira necessitamos definir o vencedor.

Movendo o state para cima

Atualmente, cada componente Square mantém o estado do jogo. Para verificar o vencedor, a melhor opção é guardar o estado do jogo no componente pai, o tabuleiro. O componente tabuleiro pode dizer para cada quadrado o que pode ser exibido via props, assim como fizemos quando passamos o número de cada quadrado. Para coletar dados de múltiplos filhos, ou para fazer dois filhos se comunicarem entre si, você precisa declarar um estado compartilhado em seu componente pai. O componente pai pode passar o estado de volta para os filhos através do uso de propriedades (props), isso mantém os componentes filhos em sincronia com os seus irmãos e também com o pai. Criar estado em um componente Pai é bem comum quando componentes React são refatorados. Vamos aproveitar essa oportunidade para testar o conceito, na prática. Vamos adicionar um construtor no Tabuleiro e definir que seu estado inicial irá ter um array com 9 posições preenchidas por nulo (null). Esses 9 nulls corresponderão aos 9 quadrados: src/index.js

class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null,
    };
  }
  render() {
    return (
      <button
        className="square"
        onClick={() => this.setState({value: 'X'})}
      >
        {this.state.value}
      </button>
    );
  }
}
class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
    };
  }
  renderSquare(i) {    
    return <Square value={i} />;
}
  render() 
    const status = 'Next player: X';
    return (
      React.createElement("div", null,
      React.createElement("div", { className: "status" }, status),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(0),
      this.renderSquare(1),
      this.renderSquare(2)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(3),
      this.renderSquare(4),
      this.renderSquare(5)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(6),
      this.renderSquare(7),
      this.renderSquare(8))));
  }
}
class Game extends React.Component {
  render() {
    return (
      React.createElement("div", { className: "game" },
      React.createElement("div", { className: "game-board" },
      React.createElement(Board, null)),
      React.createElement("div", { className: "game-info" },
      React.createElement("div", null),
      React.createElement("ol", null))));
  }
}
// ========================================
ReactDOM.render(
React.createElement(Game, null),
document.getElementById('root'));

Vamos modificar o Tabuleiro para instruir cada Quadrado individualmente qual é o valor correto ('X', 'O' ou null).

Nós já temos definidos o array de quadrados no construtor do Tabuleiro e iremos modificar o método renderSquare para definir o valor a partir do estado. Também criar a função handleClick(). Nela, nós chamamos .slice() para criar uma cópia do array de quadrados para o modificar ao invés de fazer no array existente. Depois a gente vai ver o porquê disso. src/index.js

class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null,
    };
  }
  render() {
    return (
      <button
        className="square"
        onClick={() => this.setState({value: 'X'})}
      >
        {this.state.value}
      </button>
    );
  }
}
class Board extends React.Component {
  constructor(props) { 
    super(props); 
    this.state = { 
      squares: Array(9).fill(null),
  };
  handleClick(i) {
      const squares = this.state.squares.slice();
      squares[i] = 'X';
      this.setState({squares: squares});
  }
  renderSquare(i) {    
      return <Square value={this.state.squares[i]} />;
  }
  render() 
    const status = 'Next player: X';
    return (
      React.createElement("div", null,
      React.createElement("div", { className: "status" }, status),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(0),
      this.renderSquare(1),
      this.renderSquare(2)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(3),
      this.renderSquare(4),
      this.renderSquare(5)),
      React.createElement("div", { className: "board-row" },
      this.renderSquare(6),
      this.renderSquare(7),
      this.renderSquare(8))));
  }
}
class Game extends React.Component {
  render() {
    return (
      React.createElement("div", { className: "game" },
      React.createElement("div", { className: "game-board" },
      React.createElement(Board, null)),
      React.createElement("div", { className: "game-info" },
      React.createElement("div", null),
      React.createElement("ol", null))));
  }
}
// ========================================
ReactDOM.render(
React.createElement(Game, null),
document.getElementById('root'));

É isso pessoal, nos vemos na próxima!

Código final da aula:

https://github.com/toticavalcanti/tutorial-react/tree/tic_tac_toe

Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no Facebook

Link do código fluente no Pinterest

Novamente deixo meus link de afiliados:

Hostinger

Digital Ocean

One.com

Obrigado, até a próxima e bons estudos. ;)