# react-tetris **Repository Path**: xia-dong-cloud/react-tetris ## Basic Information - **Project Name**: react-tetris - **Description**: 俄罗斯方块游戏,原项目地址:https://github.com/chvin/react-tetris - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-01-06 - **Last Updated**: 2026-01-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 中文介绍 请查看 [README.md](https://github.com/chvin/react-tetris/blob/master/README.md) ---- ## Use React, Redux, Immutable to code Tetris. ---- Tetris is a classic game that has always been enthusiastically implemented in various languages. There are many versions of it in Javascript, and using React to do Tetris has become my goal. Open [https://chvin.github.io/react-tetris/?lan=en](https://chvin.github.io/react-tetris/?lan=en) to play! ---- ### Interface preview ![Interface review](https://img.alicdn.com/tps/TB1Ag7CNXXXXXaoXXXXXXXXXXXX-320-483.gif) This is the normal speed of recording, you can see it has a smooth experience. ### Responsive ![Responsive](https://img.alicdn.com/tps/TB1AdjZNXXXXXcCapXXXXXXXXXX-480-343.gif) Not only refers to the screen adaptation, `but the change of input depending on your platform, use of the keyboard in the PC and in the phone using the touch as input`: ![phone](https://img.alicdn.com/tps/TB1kvJyOVXXXXbhaFXXXXXXXXXX-320-555.gif) ### Data persistence ![Data persistence](https://img.alicdn.com/tps/TB1EY7cNXXXXXXraXXXXXXXXXXX-320-399.gif) What's the worst can happen when you're playing stand-alone games? Power outage. The state is stored in the `localStorage` by subscribing to `store.subscribe`, which records exactly all the state. Web page refreshes, the program crashes, the phone is dead, just re-open the connection and you can continue playing. ### Redux state preview ([Redux DevTools extension](https://github.com/zalmoxisus/redux-devtools-extension)) ![Redux state preview](https://img.alicdn.com/tps/TB1hGQqNXXXXXX3XFXXXXXXXXXX-640-381.gif) Redux manages all the state that should be stored, which is a guarantee to be persisted as mentioned above. ---- The Game framework is the use of [React](https://facebook.github.io/react/) + [Redux](http://redux.js.org/), together with [Immutable.js](https://facebook.github.io/immutable-js/). ## 1. What is Immutable.js? Immutable is data that can not be changed once it is created. Any modification or addition to or deletion of an Immutable object returns a new Immutable object. ### Acquaintance: Let's look at the following code: ``` JavaScript function keyLog(touchFn) { let data = { key: 'value' }; f(data); console.log(data.key); // Guess what will be printed? } ``` If we do not look at `f`, and do not know what it did to `data`, we can not confirm what will be printed. But if `data` is *Immutable*, you can be sure that `data` haven't changed and `value` is printed: ``` JavaScript function keyLog(touchFn) { let data = Immutable.Map({ key: 'value' }); f(data); console.log(data.get('key')); // value } ``` JavaScript uses a reference assignment, meaning that the new object simply refers to the original object, changing the new will also affect the old: ``` JavaScript foo = {a: 1}; bar = foo; bar.a = 2; foo.a // 2 ``` Although this can save memory, when the application is complex, it can result in the state not being controllable, posing a big risk. The advantages of saving memory, in this case, become more harm than good. With Immutable.js the same doesn't happen: ``` JavaScript foo = Immutable.Map({ a: 1 }); bar = foo.set('a', 2); foo.get('a') // 1 ``` ### Concise: In `Redux`, it's a good practice to return a new object (array) to each `reducer`, so we often see code like this: ``` JavaScript // reducer ... return [ ...oldArr.slice(0, 3), newValue, ...oldArr.slice(4) ]; ``` In order modify one item in the array and return the new object (array), the code has this strange appearance above, and it becomes worse the deeper the data structure. Let's take a look at Immutable.js's approach: ``` JavaScript // reducer ... return oldArr.set(4, newValue); ``` Isn't it simpler? ### About “===”: We know that ```===``` operator for the `Object` and `Array` compares the reference to the address of the object rather than its "value comparison", such as: ``` JavaScript {a:1, b:2, c:3} === {a:1, b:2, c:3}; // false [1, 2, [3, 4]] === [1, 2, [3, 4]]; // false ``` To achieve the above we could only `deepCopy` and `deepCompare` to traverse the objects, but this is not only cumbersome it also harms performance. Let's check `Immutable.js` approach! ``` JavaScript map1 = Immutable.Map({a:1, b:2, c:3}); map2 = Immutable.Map({a:1, b:2, c:3}); Immutable.is(map1, map2); // true // List1 = Immutable.List([1, 2, Immutable.List[3, 4]]); List1 = Immutable.fromJS([1, 2, [3, 4]]); List2 = Immutable.fromJS([1, 2, [3, 4]]); Immutable.is(List1, List2); // true ``` It's smooth like a breeze blowing. React has a big trick when it comes to performance tuning. It uses `shouldComponentUpdate()` to check (as the name says) if the component should be re-rendered, it returns `true` by default, which always executes the `render()` method followed by the Virtual DOM comparison. If we don't return a new object when making state updates, we would have to use `deepCopy` and `deepCompare` to calculate if the new state is equal to the previous one, the consumption of the performance is not worth it. With Immutable.js, it's easy to compare deep structures using the method above. For Tetris, imagine that the board is a `two-dimensional array`. The square that can be moved is `shape (also a two-dimensional array) + coordinates`. The superposition of the board and the box is composed of the final result of `Matrix`. The properties above are built by `Immutable.js`, through its comparison method, you can easily write `shouldComponentUpdate`. Source Code:[/src/components/matrix/index.js#L35](https://github.com/chvin/react-tetris/blob/master/src/components/matrix/index.js#L35) Immutable learning materials: * [Immutable.js](http://facebook.github.io/immutable-js/) * [Immutable Detailed and React in practice](https://github.com/camsong/blog/issues/3) ---- ## 2. How to use Immutable.js in Redux Goal: `state` -> Immutable. Important plug-ins: [gajus/redux-immutable](https://github.com/gajus/redux-immutable) Will be provided by the original Redux combineReducers provided by the above plug-ins: ``` JavaScript // rootReducers.js // import { combineReducers } from 'redux'; // The old method import { combineReducers } from 'redux-immutable'; // The new method import prop1 from './prop1'; import prop2 from './prop2'; import prop3 from './prop3'; const rootReducer = combineReducers({ prop1, prop2, prop3, }); // store.js // Create a store method and the same general import { createStore } from 'redux'; import rootReducer from './reducers'; const store = createStore(rootReducer); export default store; ``` Through the new `combineReducers` the store object will be stored as an Immutable.js object, the container will be slightly different, but this is what we want: ``` JavaScript const mapStateToProps = (state) => ({ prop1: state.get('prop1'), prop2: state.get('prop2'), prop3: state.get('prop3'), next: state.get('next'), }); export default connect(mapStateToProps)(App); ``` ---- ## 3. Web Audio Api There are many different sound effects in the game, but in fact we keep only a reference to a sound file: [/build/music.mp3](https://github.com/chvin/react-tetris/blob/master/build/music.mp3). With the help of `Web Audio Api`, you can play audio in millisecond precision, with a high frequency, which is not possible with the `