Tetris is a classic game that has always been implemented by various programming languages. There are many versions of JavsScript. Tetris with React became one of my goals.

Stamp: chvin. Making. IO/react – tetri… Have some fun!

Open source: github.com/chvin/react…


Results the preview

Results the preview

Normal speed recording, smooth experience.

responsive

responsive

It refers not only to screen adaptation, but also to responsive manipulation using the keyboard on the PC and the finger on the phone:

Mobile phone

Data persistence

Data persistence

What are you most afraid of playing PC games? Without electricity. State is stored in localStorage by subscribing to Store. subscribe, keeping an accurate record of all states. The web page has been closed and refreshed, the application has crashed, the phone is out of battery, re-open the connection, you can continue.

Redux Status Preview (Redux DevTools extension)

Redux status preview

The Redux design manages all the required state, which is the guarantee of persistence above.


The React + Redux framework uses imdux as an instance of Redux state. React and Redux can be learned from Redux and React.

1. What is Immutable?

Immutable is data that, once created, cannot be changed. Any modification or addition or deletion of an Immutable object returns a new Immutable object.

First:

Let’s look at the following code:

function keyLog(touchFn) {
  let data = { key: 'value' };
  f(data);
  console.log(data.key); // Guess what will be printed?
}Copy the code

Without looking at F, you don’t know what it does to data, and you can’t confirm what will be printed. But if data is Immutable, you can be sure to print value:

function keyLog(touchFn) {
  let data = Immutable.Map({ key: 'value' });
  f(data);
  console.log(data.get('key'));  // value
}Copy the code

Object and Array in JavaScript use reference assignment. The new Object simply refers to the original Object. Changing the new Object also affects the old:

foo = {a: 1};  bar = foo;  bar.a = 2;
foo.a / / 2Copy the code

Although this can save memory, but when the application is complex, resulting in uncontrollable state, is a great hidden danger, saving memory advantages become more than worth the loss.

Immutable is not the same, corresponding:

foo = Immutable.Map({ a: 1 });  bar = foo.set('a'.2);
foo.get('a') / / 1Copy the code

Simple:

In Redux, it is optimal to return a new object (array) per reducer, so we often see code like this:

// reducer. return [ ...oldArr.slice(0.3), newValue, ... oldArr.slice(4)];Copy the code

In order to return new objects (arrays), you have to have the odd look above, which can get trickier when using deeper data structures. Let’s look at Immutable:

// reducer. return oldArr.set(4, newValue);Copy the code

Isn’t that neat?

About “= = =” :

=== === === === === =

{a:1.b:2.c:3} = = = {a:1.b:2.c:3}; // false
[1.2[3.4= = = []]1.2[3.4]].// falseCopy the code

Only deepCopy and deepCompare can be used for traversal comparison, which is not only troublesome but also good performance.

Let’s feel the Immutable way!

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); // trueCopy the code

There seems to be a breeze blowing.

A great way to optimize React is to use shouldComponentUpdate(), but it returns true by default and always executes render(), followed by a Virtual DOM comparison.

ShouldComponentUpdate = true/false; shouldComponentUpdate = true/false; shouldComponentUpdate = true/false After Immutable, it is easy to compare deep structures using the above method.

For Tetris, think of the board as a two-dimensional array, and the moving squares as shapes (also two-dimensional arrays)+ coordinates. The superposition of the checkerboard and squares forms the final Matrix. The above attributes are constructed Immutable, and shouldComponentUpdate is easy to write using its comparison method. Source: / SRC/components/matrix/index js# L35

Immutable mutable

  • Immutable.js
  • Immutable; React; Immutable

How to use Immutable in Redux

Target: make state -> Immutable. Key library: Gajus /redux-immutable combineReducers redux-immutable

// rootReduers.js
// import { combineReducers } from 'redux'; // The old way
import { combineReducers } from 'redux-immutable'; // New method

import prop1 from './prop1';
import prop2 from './prop2';
import prop3 from './prop3';

const rootReducer = combineReducers({
  prop1, prop2, prop3,
});


// store.js
// Create store as usual
import { createStore } from 'redux';
import rootReducer from './reducers';

const store = createStore(rootReducer);
export default store;Copy the code

The new combineReducers will convert store objects to Immutable, and will be slightly different when used in Containers (but that’s what we want) :

const mapStateToProps = (state) = > ({
  prop1: state.get('prop1'),
  prop2: state.get('prop2'),
  prop3: state.get('prop3'),
  next: state.get('next')});export default connect(mapStateToProps)(App);Copy the code

3. Web Audio Api

There are a lot of different sound effects in the game, and only one sound file is actually referenced: /build/music.mp3. The Web Audio Api makes it possible to play sound with millisecond accuracy at high frequencies that the < Audio > tag does not. Hold down the D-pad to move a block while playing and you can hear a high-frequency sound effect.

Web audio advanced

WAA is a new set of relatively independent interface system, audio files have higher processing permissions and more professional built-in audio effects, is the W3C recommended interface, professional processing of “sound speed, volume, environment, timbre visualization, high frequency, tone orientation” and other requirements, the following figure describes the use of WAA process.

process

Where Source represents an audio Source, Destination represents the final output, and Destination is synthesized from multiple sources. Source code: / SRC /unit/music.js Ajax load MP3, and to WAA, control the playback process.

WAA support in the latest 2 versions of each browser (CanIUse)

Browser compatibility

You can see IE camp can’t be used with most Android, other OK.

The Web Audio Api

  • | MDN Web API interface
  • Getting Started with Web Audio API

4. Optimization of game experience

  • Technology:
    • / SRC /unit/event.js; / SRC /unit/event.js;
    • Moving from side to side can delay the speed of falling, but the delay is smaller when moving against the wall. Delay ensures a complete horizontal movement in a row at speed 6;
    • Register the buttons simultaneouslytouchstartandmousedownEvents for responsive play. whentouchstartDoes not trigger when it occursmousedownAnd whenmousedownOccurs when the event element can not fire due to the mouse moving awaymouseup, will listen simultaneouslymouseoutsimulationmouseup. The source code:/src/components/keyboard/index.js;
    • Listen to thevisibilitychangeEvent, when the page is hidden \ switch, the game will not play, switch back will continue, thisfocusStates are also written into Redux. So when you play with your phoneThe phone, the game progress will be saved; You don’t hear Gameover when you’re playing a game on your PC. It’s kind of likeiosSwitching applications.
    • inanyRefresh the page at any time (e.g. eliminate blocks, end of game) can also restore the current state;
    • The only images used in the game are
      image

      , everything else is CSS;

    • Compatible with Chrome, Firefox, IE9+, Edge, etc.
  • Game:
    • You can specify the initial board (ten levels) and speed (six levels) before the game starts;
    • A single elimination earns 100 points for 1 line, 300 points for 2 lines, 700 points for 3 lines, and 1,500 points for 4 lines.
    • [Fixed] Block drop speed increases with the number of eliminated rows (one level for every 20 rows)

5. Experience sorting in development

  • For all thecomponentWrite theshouldComponentUpdateThe performance of mobile phones has been significantly improved. ShouldComponentUpdate shouldComponentUpdate shouldComponentUpdate shouldComponentUpdate shouldComponentUpdate shouldComponentUpdate shouldComponentUpdate
  • Stateless component(Stateless Functional Components) has no life cycle. Because of the above factor, all components should have a life cycle shouldComponentUpdate, so stateless components are not used.
  • inwebpack.config.jsThe devServer property inHost: '0.0.0.0', can be accessed at development time using IP, not limited to localhost;
  • In the storystoreIt is not only through connect that methods are passed tocontainer, can jump out of the component, in another file out to do flow control (dispatch), source code:/src/control/states.js;
  • Persisting react+redux is very convenient, just store the REdux state and read it when each reduer is initialized.
  • By configuring.eslintrc.jsWith webpack. Config. JsIs integrated into the projectESLintInspection. Using ESLint allows code to be written to specifications, effectively controlling code quality. Nonconforming code can be found at development time (or build time) through the IDE and console. Reference:Airbnb: React usage specifications;

6, summary

  • As a React application for practice, many details can be optimized and polished in the implementation process. This is the time to test the carefulness and skill of a front-end engineer.
  • The optimization direction is both React itself, such as which states are stored by Redux and which states are given to component states. Out of the frame and there are many features of the product can play, in order to meet your needs, these will naturally promote the development of technology.
  • A project from scratch, function slowly accumulated, will be built into a high-rise, do not be afraid of difficult, have an idea to knock it up. ^_^

7. Control process

Control process


This article joins the nuggets technical essay: juejin.cn/post/684490…