In the previous section, we implemented a simple performance optimization, but because we need a deep copy and property comparison, the performance is still poor, so we use immutable.js written by Facebook God for further optimization
Immutable collection of immutable.js JavaScript
Each modification will return a new object, where the previous object will always remain. It provides some common data types for us to use. The common data types are as follows:
- List: an ordered index set, similar to Array in JavaScript.
- Map: similar to Object in JavaScript.
Here are only two most commonly used data types. If you want to know more types, you can go to immutabl official website see
- Simple approach
let immutable = require('immutable') let {Map, List} = immutable let obj1 = Map({name: 'leo', age: 12) console.log(obj1) // Map { "name": "leo", "age": 12 } let obj2 = obj1.set('name', 'hello') // For simple use, the returned object is different from the previous object, as shown in the following case console.log(obj2) // Map { "name": "hello", "age": 12 } console.log(obj1 === obj2) // false
- Properties will be shared
let immutable = require('immutable') let {Map, List, fromJS} = immutable let obj1 = fromJS({ name: 'leo', age: 12, home: { name: 'shenzhen' } }) let obj2 = obj1.set('name', 'hello') // Properties will be shared console.log(obj1.home === obj2.home) // true // Get the number of properties of the object console.log(obj1.size) // 3 console.log(obj1.count()) // 3
- Pain points of map
Although the map is easy to use, the map can only execute one layer. We will report an error for the level 2 update attribute. We need to use fromjs to process the object
Set value set is used for one layer and setIn is used for multiple layers
/Value: get is used at one level and getIN is used at multiple levels
let immutable = require('immutable') let {Map, fromJS} = immutable let obj1 = fromJS({ name: 'leo', age: 12, home: { name: 'shenzhen' } }) let obj2 = obj1.set('name', 'hello') let obj3 = obj1.setIn(['home', 'name'], 'new Name') console.log(obj3) // Map { "name": "leo", "age": 12, "home": Map { "name": "new Name" } } console.log(obj3.getIn(['home', 'name'])) // new Name
- update with new value
let immutable = require('immutable') let {Map, fromJS} = immutable let obj1 = fromJS({ name: 'leo', age: 12, home: { name: 'shenzhen' } }) let obj2 = obj1.set('name', 'hello') let obj3 = obj1.setIn(['home', 'name'], 'new Name') let obj4 = obj3.update('age', val => val + 1) console.log(obj3) // Map { "name": "leo", "age": 12, "home": Map { "name": "new Name" } } console.log(obj3.getIn(['home', 'name'])) // new Name console.log(obj4) // Map { "name": "leo", "age": 13, "home": Map { "name": "new Name" } }
- Delete a property
let immutable = require('immutable') let {Map, fromJS} = immutable let obj1 = fromJS({ name: 'leo', age: 12, home: { name: 'shenzhen' } }) let obj2 = obj1.set('name', 'hello') let obj3 = obj1.setIn(['home', 'name'], 'new Name') let obj4 = obj3.update('age', val => val + 1) let obj5 = obj4.delete('age') console.log(obj5) // Map { "name": "leo", "home": Map { "name": "new Name" } }
- Empty object
let immutable = require('immutable') let {Map, fromJS} = immutable let obj1 = fromJS({ name: 'leo', age: 12, home: { name: 'shenzhen' } }) let obj2 = obj1.set('name', 'hello') let obj3 = obj1.setIn(['home', 'name'], 'new Name') let obj4 = obj3.update('age', val => val + 1) let obj5 = obj4.delete('age') let obj6 = obj4.clear() console.log(obj6) // Map {}
- merge object
let immutable = require('immutable') let {Map, fromJS} = immutable let obj1 = fromJS({ name: 'leo', age: 12, home: { name: 'shenzhen' } }) let obj2 = obj1.set('name', 'hello') let obj3 = obj1.setIn(['home', 'name'], 'new Name') let obj4 = obj3.update('age', val => val + 1) let obj5 = obj4.delete('age') let obj6 = obj4.clear() let obj7 = obj6.merge({name: 'world', gender: 'man'}) console.log(obj7) // Map { "name": "world", "gender": "man" }
- Type conversion
let immutable = require('immutable') let {Map, fromJS} = immutable let obj1 = fromJS({ name: 'leo', age: 12, home: { name: 'shenzhen' } }) let obj2 = obj1.set('name', 'hello') let obj3 = obj1.setIn(['home', 'name'], 'new Name') let obj4 = obj3.update('age', val => val + 1) let obj5 = obj4.delete('age') let obj6 = obj4.clear() let obj7 = obj6.merge({name: 'world', gender: 'man'}) console.log(obj7.toJS()) // { name: 'world', gender: 'man' } console.log(obj7.toJSON()) // { name: 'world', gender: 'man' } console.log(obj7.toObject()) // { name: 'world', gender: 'man' }
Simple use of immutable.js list data type
Operation method is similar to array
let immutable = require('immutable') let { Map, List, fromJS } = immutable let arr1 = List([1, 2, 3]) let arr2 = arr1.push(4) let arr3 = arr2.pop() let arr4 = arr3.map(item => item * 2) let arr5 = arr4.filter(item => item < 5) console.log(arr5) // List [ 2, 4 ] let arr6 = arr5.update(1, val => val * 100) console.log(arr6) // List [ 2, 400 ] let arr7 = arr6.delete(0) console.log(arr7) // List [ 400 ] let arr8 = arr7.push(12) console.log(arr8) // List [ 400, 12 ] let arr9 = arr8.last() console.log(arr9) // 12
immutable.js comparison method
let {is, Map} = require('immutable') let obj1 = Map({name: 'hello', age: 12}) let obj2 = Map({name: 'hello', age: 12}) console.log(Object.is(obj1, obj2)) // false // immutable's is method compares values console.log(is(obj1, obj2)) // true
PureComponent component modification
import React, { Component } from 'react'; import { is } from "immutable"; class PureComponent extends Component{ shouldComponentUpdate (nextProps, nextState) { // Return! Delete this line // Get the old and new status, and compare them at the back let oldState = this.state || {} let newState = nextState ? nextState : {} // If the property keys are different, update the page directly let keys = Object.keys(newState) if (Object.keys(oldState).length !== keys.length) return true; for (var i = 0, len = keys.length; i < len; i++) { let key = keys[i] // If the property values are different, the status needs to be updated if(!is(newState[key], oldState[key])) return true } return false } } export default PureComponent
index.js component modification
import React,{Component} from 'react'; import ReactDOM from 'react-dom'; import PureComponent from './PureComponent'; import _ from 'lodash' let immutable = require('immutable') let { Map, List, fromJS } = immutable // The principle of PureComponent component optimization is to rewrite the shouldComponentUpdate. If the old state object ang and the new state are not the same for the play, the page will be refreshed /** * 1.Every time a new object is generated, deep cloning consumes a lot of memory */ class Counter extends PureComponent{ state = { counter: Map({ number: 0}) } handleClick = event => { // Optimized deep copy for memory savings // let state = _.cloneDeep(this.state) delete this line let amount = this.amount.value ? Number(this.amount.value) : 0 // Add the following status let newState = { ...this.state, counter: this.state.counter.update('number', val => val + amount)} this.setState(newState) } render () { console.log('render') return ( <div> <p>{this.state.counter.get('number')}</p> <input ref={input => this.amount = input}/> <button onClick={this.handleClick}>add</button> </div> ) } } ReactDOM.render(<Counter></Counter>, document.getElementById('root'));
summary
Through simple processing, it will greatly improve the performance of the solution