diff --git a/README.md b/README.md index ffc9e9a8..da0e5a33 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,53 @@ -### English introduction +### Introdução em Inglês Please view [README-EN.md](https://github.com/chvin/react-tetris/blob/master/README-EN.md) ---- -## 用React、Redux、Immutable做俄罗斯方块 +## Tetris feito com React, Redux e Immutable ---- -俄罗斯方块是一直各类程序语言热衷实现的经典游戏,JavaScript的实现版本也有很多,用React 做好俄罗斯方块则成了我一个目标。 +Tetris é um clássico jogo que desenvolvedores adoram recriar em várias linguagens de programação. Há muitas versões em JavaScript, mas fazer uma versão com React se tornou meu objetivo. -戳:[https://chvin.github.io/react-tetris/](https://chvin.github.io/react-tetris/) 玩一玩! +Clique aqui para jogar: [https://chvin.github.io/react-tetris/](https://chvin.github.io/react-tetris/) ---- -### 效果预览 -![效果预览](https://img.alicdn.com/tps/TB1Ag7CNXXXXXaoXXXXXXXXXXXX-320-483.gif) +### Visualização do resultado +![Visualização do resultado](https://img.alicdn.com/tps/TB1Ag7CNXXXXXaoXXXXXXXXXXXX-320-483.gif) -正常速度的录制,体验流畅。 +Gravado em velocidade normal, experiência fluida. -### 响应式 -![响应式](https://img.alicdn.com/tps/TB1AdjZNXXXXXcCapXXXXXXXXXX-480-343.gif) +### Responsividade +![Responsividade](https://img.alicdn.com/tps/TB1AdjZNXXXXXcCapXXXXXXXXXX-480-343.gif) -不仅指屏幕的自适应,而是`在PC使用键盘、在手机使用手指的响应式操作`: +Não apenas se adapta à tela, mas também permite `usar o teclado no PC e o toque no celular`: -![手机](https://img.alicdn.com/tps/TB1kvJyOVXXXXbhaFXXXXXXXXXX-320-555.gif) +![Celular](https://img.alicdn.com/tps/TB1kvJyOVXXXXbhaFXXXXXXXXXX-320-555.gif) -### 数据持久化 -![数据持久化](https://img.alicdn.com/tps/TB1EY7cNXXXXXXraXXXXXXXXXXX-320-399.gif) +### Persistência de dados +![Persistência de dados](https://img.alicdn.com/tps/TB1EY7cNXXXXXXraXXXXXXXXXXX-320-399.gif) -玩单机游戏最怕什么?断电。通过订阅 `store.subscribe`,将state储存在localStorage,精确记录所有状态。网页关了刷新了、程序崩溃了、手机没电了,重新打开连接,都可以继续。 +O maior medo de jogar offline é perder progresso. Através do `store.subscribe`, o estado é salvo no localStorage, registrando todos os estados precisamente. Mesmo que a página seja fechada ou atualizada, ou o celular fique sem bateria, você pode continuar de onde parou. -### Redux 状态预览([Redux DevTools extension](https://github.com/zalmoxisus/redux-devtools-extension)) -![Redux状态预览](https://img.alicdn.com/tps/TB1hGQqNXXXXXX3XFXXXXXXXXXX-640-381.gif) +### Visualização do estado Redux ([Redux DevTools extension](https://github.com/zalmoxisus/redux-devtools-extension)) +![Visualização do estado Redux](https://img.alicdn.com/tps/TB1hGQqNXXXXXX3XFXXXXXXXXXX-640-381.gif) -Redux设计管理了所有应存的状态,这是上面持久化的保证。 +O Redux gerencia todos os estados armazenados, garantindo a persistência mencionada acima. ---- -游戏框架使用的是 React + Redux,其中再加入了 Immutable,用它的实例来做来Redux的state。(有关React和Redux的介绍可以看:[React入门实例](http://www.ruanyifeng.com/blog/2015/03/react.html)、[Redux中文文档](https://camsong.github.io/redux-in-chinese/index.html)) +A estrutura do jogo usa React + Redux, com Immutable para gerenciar o estado do Redux. (Para mais informações sobre React e Redux, veja: [Introdução ao React](http://www.ruanyifeng.com/blog/2015/03/react.html), [Documentação do Redux em Chinês](https://camsong.github.io/redux-in-chinese/index.html)) -## 1、什么是 Immutable? -Immutable 是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。 +## 1. O que é Immutable? +Immutable é um tipo de dado que, uma vez criado, não pode ser alterado. Qualquer modificação, adição ou remoção de um objeto Immutable retorna um novo objeto Immutable. -### 初识: -让我们看下面一段代码: +### Introdução: +Vamos ver o seguinte código: ``` JavaScript function keyLog(touchFn) { let data = { key: 'value' }; f(data); - console.log(data.key); // 猜猜会打印什么? + console.log(data.key); // O que será impresso? } ``` -不查看f,不知道它对 `data` 做了什么,无法确认会打印什么。但如果 `data` 是 Immutable,你可以确定打印的是 `value`: +Sem ver a função f, não sabemos o que ela faz com `data`, então não podemos ter certeza do valor impresso. Mas se `data` for Immutable, podemos ter certeza de que imprimirá `value`: ``` JavaScript function keyLog(touchFn) { let data = Immutable.Map({ key: 'value' }); @@ -56,21 +56,21 @@ function keyLog(touchFn) { } ``` -JavaScript 中的`Object`与`Array`等使用的是引用赋值,新的对象简单的引用了原始对象,改变新也将影响旧的: +Em JavaScript, `Object` e `Array` usam atribuição por referência. Um novo objeto referencia o objeto original, de modo que alterar o novo objeto também altera o antigo: ``` JavaScript foo = {a: 1}; bar = foo; bar.a = 2; foo.a // 2 ``` -虽然这样做可以节约内存,但当应用复杂后,造成了状态不可控,是很大的隐患,节约的内存优点变得得不偿失。 +Embora isso economize memória, pode causar estados incontroláveis em aplicativos complexos, transformando a economia de memória em um problema. -Immutable则不一样,相应的: +Com Immutable, é diferente: ``` JavaScript foo = Immutable.Map({ a: 1 }); bar = foo.set('a', 2); foo.get('a') // 1 ``` -### 简洁: -在`Redux`中,它的最优做法是每个`reducer`都返回一个新的对象(数组),所以我们常常会看到这样的代码: +### Simplificação: +No `Redux`, a melhor prática é que cada `reducer` retorne um novo objeto (array). Muitas vezes vemos código assim: ``` JavaScript // reducer ... @@ -80,24 +80,23 @@ return [ ...oldArr.slice(4) ]; ``` -为了返回新的对象(数组),不得不有上面奇怪的样子,而在使用更深的数据结构时会变的更棘手。 -让我们看看Immutable的做法: +Para retornar um novo objeto (array), temos que escrever código estranho como o acima. Com estruturas de dados mais profundas, isso se torna ainda mais complicado. Com Immutable, fica assim: ``` JavaScript // reducer ... return oldArr.set(4, newValue); ``` -是不是很简洁? +Muito mais simples, não? -### 关于 “===”: -我们知道对于`Object`与`Array`的`===`比较,是对引用地址的比较而不是“值比较”,如: +### Sobre “===”: +Sabemos que a comparação `===` para `Object` e `Array` é baseada na referência de endereço, não no valor: ``` JavaScript {a:1, b:2, c:3} === {a:1, b:2, c:3}; // false [1, 2, [3, 4]] === [1, 2, [3, 4]]; // false ``` -对于上面只能采用 `deepCopy`、`deepCompare`来遍历比较,不仅麻烦且好性能。 +Para comparar esses valores, precisaríamos de `deepCopy` ou `deepCompare`, que são trabalhosos e consomem muita performance. -我们感受来一下`Immutable`的做法! +Com Immutable, a comparação fica assim: ``` JavaScript map1 = Immutable.Map({a:1, b:2, c:3}); map2 = Immutable.Map({a:1, b:2, c:3}); @@ -108,28 +107,25 @@ List1 = Immutable.fromJS([1, 2, [3, 4]]); List2 = Immutable.fromJS([1, 2, [3, 4]]); Immutable.is(List1, List2); // true ``` -似乎有阵清风吹过。 +Muito mais eficiente! -React 做性能优化时有一个`大招`,就是使用 `shouldComponentUpdate()`,但它默认返回 `true`,即始终会执行 `render()` 方法,后面做 Virtual DOM 比较。 +Quando otimizamos a performance do React, uma técnica importante é `shouldComponentUpdate()`, que por padrão retorna `true`, sempre executando o método `render()`. Para calcular `shouldComponentUpdate` corretamente com objetos nativos, precisaríamos de `deepCopy` e `deepCompare`, o que consome muita performance. Com Immutable, a comparação de estruturas profundas é simples. -在使用原生属性时,为了得出shouldComponentUpdate正确的`true` or `false`,不得不用deepCopy、deepCompare来算出答案,消耗的性能很不划算。而在有了Immutable之后,使用上面的方法对深层结构的比较就变的易如反掌。 +No Tetris, imagine que o tabuleiro é uma `matriz 2D`, e a peça móvel é uma `forma (também uma matriz 2D)` + `coordenadas`. A combinação do tabuleiro e da peça forma o resultado final `Matrix`. Essas propriedades são construídas com Immutable, facilitando a escrita de `shouldComponentUpdate`. Código-fonte: [/src/components/matrix/index.js#L35](https://github.com/chvin/react-tetris/blob/master/src/components/matrix/index.js#L35) -对于「俄罗斯方块」,试想棋盘是一个`二维数组`,可以移动的方块则是`形状(也是二维数组)`+`坐标`。棋盘与方块的叠加则组成了最后的结果`Matrix`。游戏中上面的属性都由`Immutable`构建,通过它的比较方法,可以轻松写好`shouldComponentUpdate`。源代码:[/src/components/matrix/index.js#L35](https://github.com/chvin/react-tetris/blob/master/src/components/matrix/index.js#L35) - -Immutable学习资料: +Recursos para aprender Immutable: * [Immutable.js](http://facebook.github.io/immutable-js/) -* [Immutable 详解及 React 中实践](https://github.com/camsong/blog/issues/3) - +* [Guia detalhado e práticas no React com Immutable](https://github.com/camsong/blog/issues/3) ---- -## 2、如何在Redux中使用Immutable -目标:将`state` -> Immutable化。 -关键的库:[gajus/redux-immutable](https://github.com/gajus/redux-immutable) -将原来 Redux提供的combineReducers改由上面的库提供: +## 2. Como usar Immutable no Redux +Objetivo: Tornar o `state` Immutable. +Biblioteca-chave: [gajus/redux-immutable](https://github.com/gajus/redux-immutable) +Troque `combineReducers` do Redux pela biblioteca acima: ``` JavaScript // rootReducers.js -// import { combineReducers } from 'redux'; // 旧的方法 -import { combineReducers } from 'redux-immutable'; // 新的方法 +// import { combineReducers } from 'redux'; // Método antigo +import { combineReducers } from 'redux-immutable'; // Novo método import prop1 from './prop1'; import prop2 from './prop2'; @@ -141,14 +137,14 @@ const rootReducer = combineReducers({ // store.js -// 创建store的方法和常规一样 +// Criação da store é igual ao método convencional import { createStore } from 'redux'; import rootReducer from './reducers'; const store = createStore(rootReducer); export default store; ``` -通过新的`combineReducers`将把store对象转化成Immutable,在container中使用时也会略有不同(但这正是我们想要的): +O novo `combineReducers` transforma o objeto store em Immutable. No container, o uso também será ligeiramente diferente (mas é exatamente o que queremos): ``` JavaScript const mapStateToProps = (state) => ({ @@ -161,82 +157,78 @@ export default connect(mapStateToProps)(App); ``` ---- -## 3、Web Audio Api -游戏里有很多不同的音效,而实际上只引用了一个音效文件:[/build/music.mp3](https://github.com/chvin/react-tetris/blob/master/build/music.mp3)。借助`Web Audio Api`能够以毫秒级精确、高频率的播放音效,这是`