Aula 03 – React – Imutabilidade
Aula 03 – React – Imutabilidade
Voltar para página principal do blog
Todas as aulas desse curso
Aula 02 Aula 04
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/
Por que imutabilidade é Importante
No código do exemplo usamos o método slice() para criar uma cópia do array de quadrados ao invés de modificar o existente.
Iremos agora discutir imutabilidade e porque ela é importante de se aprender.
Geralmente existem duas maneiras de se alterar dados.
A primeira é mudar (mutar) o dado alterando diretamente seu valor.
A segunda maneira é substituir o dado antigo por uma nova cópia com as alterações desejadas.
Mudando dados com mutação
let player = {score: 1, name: 'Jeff'};
player.score = 2;
// Agora o player é {score: 2, name: 'Jeff'}
Mudando dados sem mutação
let player = {score: 1, name: 'Jeff'};
let newPlayer = Object.assign({}, player, {score: 2});
// Agora o player não sofreu alteração, mas o newPlayer é {score: 2, name: 'Jeff'}
// Ou então se você estiver usando a sintaxe "object spread", você pode escrever:
// let newPlayer = {...player, score: 2};
O resultado final é o mesmo, mas, por não mudar (ou alterar os dados) diretamente, ganhamos vários benefícios.
Complexidade das features se tornam mais simples
Imutabilidades faz a complexidade das features se tornarem bem mais simples de serem implementadas.
Mais a frente, implementaremos uma feature de “máquina do tempo” que nos permitirá revisar o histórico do jogo da velha e “voltar” as jogadas anteriores.
Essa funcionalidade não está ligada somente ao jogo, uma habilidade de desfazer e refazer certas ações é um requisito comum em aplicações.
Evitar mutação nos permite manter o histórico das versões anteriores do jogo intacta e reutiliza-las mais tarde.
Detectar Mudanças
Detectar mudanças e objetos que foram mudados é difícil, pois, eles são modificados diretamente.
Essa detecção requer um objeto que foi alterado para ser comparado com as cópias das suas próprias versões anteriores e a árvore inteira do object para ser cruzada.
Detectar mudanças em objetos imutáveis é consideravelmente fácil.
Se ele for imutável e o que está sendo referenciado for diferente do anterior, concluímos que o objeto foi alterado.
Determinar Quando Re-renderizar no React
O principal benefício da imutabilidade é que ela ajuda a construir componentes puros em React.
Dados imutáveis podem facilmente determinar se foram feitas mudanças, que ajudarão a decidir quando um componente precisa ser renderizado novamente.
Componentes de Função
Nós vamos agora mudar o Square para ser um componente de função.
Em React, componentes de função são os mais simples de serem escritos, contém apenas um método render e não possuem seu próprio state.
Ao invés de definir uma classe que extende de React.Component, nós podemos escrever uma função que recebe props como entrada e retorna o que deverá ser renderizado.
Esse tipo de componente é menos tedioso de escrever do que classes e muitos componentes podem ser expressados desta maneira.
Troque a classe Square por esta função:
src/index.js
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.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]} />;
}
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(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'));
Nos modificamos this.props para props nas duas vezes em que ele aparece.
Nota
Quando modificamos Square para ser um componente funcional, também modificamos onClick={() => this.props.onClick()} para uma versão mais curta:
onClick={props.onClick}
Note a ausência dos parentêses em ambos os lados.
Alternando os jogadores
Agora precisamos consertar um defeito óbvio em nosso Jogo da Velha:
Os “O“s não podem ser marcados no tabuleiro.
Vamos definir a primeira jogada para ser “X” por padrão.
Podemos definir esse padrão modificando o state inicial no construtor do nosso tabuleiro (Board).
src/index.js
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
xIsNext: true,
};
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = 'X'; this.setState({squares: squares}); }
renderSquare(i) {
return <Square value={this.state.squares[i]} />;
}
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(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'));
Sempre que um jogador fizer uma jogada, xIsNext (um boolean) será trocado para determinar qual jogador será o próximo e o state do jogo será salvo.
Nós atualizaremos a função handleClick() do Board para trocar o valor de xIsNext:
src/index.js
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
xIsNext: true,
};
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(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'));
Com essa mudança,”X“s e “O“s serão alternados.
Tente!
Também vamos modificar o texto de “status” na função render() do Board, para que ela passe a exibir quem jogará no próxima jogada.
src/index.js
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
xIsNext: true,
};
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>
);
}
render()
const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
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'));
Por essa aula é só! 😉
Aula 02 Aula 04
Todas as aulas desse curso
Voltar para página principal do blog
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. 😉