使用React開發的時候,咱們請求服務器拿回來一個複雜的數據,咱們在render裏去處理這個數據,可是state和props頻繁修改會觸發render,每次觸發render,數據都要去處理一次,每次處理都是對性能的損耗javascript
舉個例子:把大於18歲的人列出來java
class Example extends Component { ... render() { const { dataList } = this.props; const newDataList = dataList.filter((item) => item.age > 18); return ( <div> {newDataList.map((item, i) => <p key={i}>{item.name}:{item.age}歲</p> )} </div> ) } ... }
從例子中咱們看到render中咱們處理數據,可是每次state和props的修改都會觸發render,都會去處理數據dataList,生成新的數據newDataList,每次處理都是對性能的損耗!git
每次調用函數把你的傳參和結果記錄下來,遇到相同的傳參,就直接返回記錄緩存的結果,不用再去調用函數處理數據!github
import memoizeOne from 'memoize-one'; const add = (a, b) => a + b; const memoizedAdd = memoizeOne(add); memoizedAdd(1, 2); // 3 memoizedAdd(1, 2); // 3 // Add 函數並無執行: 前一次執行的結果被返回 memoizedAdd(2, 3); // 5 // Add 函數再次被調用,返回一個新的結果 memoizedAdd(2, 3); // 5 // Add 函數並無執行: 前一次執行的結果被返回 memoizedAdd(1, 2); // 3 // Add 函數再次被調用,返回一個新的結果
咱們能夠發現連續兩次相同傳參,第二次會直接返回上次的結果,每次傳參不同,就直接調用函數返回新的結果,會丟失以前的記錄,並非徹底記憶,這也是個不足點!緩存
根據上的例子,咱們對那個例子進行修改,使用memoize-one提高React的性能服務器
import memoize from "memoize-one"; class Example extends Component { ... filter = memoize((dataList, age) => dataList.filter((item) => item.age > age)) render() { const { dataList } = this.props; const newDataList = this.filter(dataList, 18) return ( <div> ... {newDataList.map((item, i) => <p key={i}>{item.name}:{item.age}歲</p> )} ... </div> ) } ... }
memoize-one是採用閉包來緩存數據的閉包
type EqualityFn = (a: mixed, b: mixed) => boolean; const simpleIsEqual: EqualityFn = (a: mixed, b: mixed): boolean => a === b; export default function <ResultFn: (...Array<any>) => mixed>(resultFn: ResultFn, isEqual?: EqualityFn = simpleIsEqual): ResultFn { let lastThis: mixed; // 用來緩存上一次result函數對象 let lastArgs: Array<mixed> = []; // 用來緩存上一次的傳參 let lastResult: mixed; // 用來緩存上一次的結果 let calledOnce: boolean = false; // 是否以前調用過 // 判斷兩次調用的時候的參數是否相等 // 這裏的 `isEqual` 是一個抽象函數,用來判斷兩個值是否相等 const isNewArgEqualToLast = (newArg: mixed, index: number): boolean => isEqual(newArg, lastArgs[index]); const result = function (...newArgs: Array<mixed>) { if (calledOnce && lastThis === this && newArgs.length === lastArgs.length && newArgs.every(isNewArgEqualToLast)) { // 返回以前的結果 return lastResult; } calledOnce = true; // 標記已經調用過 lastThis = this; // 從新緩存result對象 lastArgs = newArgs; // 從新緩存參數 lastResult = resultFn.apply(this, newArgs); // 從新緩存結果 return lastResult; // 返回新的結果 }; // 返回閉包函數 return (result: any); }
通常兩個對象比較是否相等,咱們不能用===或者==來處理,memoize-one容許用戶自定義傳入判斷是否相等的函數,好比咱們可使用lodash的isEqual來判斷兩次參數是否相等app
import memoizeOne from 'memoize-one'; import deepEqual from 'lodash.isEqual'; const identity = x => x; const defaultMemoization = memoizeOne(identity); const customMemoization = memoizeOne(identity, deepEqual); const result1 = defaultMemoization({foo: 'bar'}); const result2 = defaultMemoization({foo: 'bar'}); result1 === result2 // false - 索引不一樣 const result3 = customMemoization({foo: 'bar'}); const result4 = customMemoization({foo: 'bar'}); result3 === result4 // true - 參數經過lodash.isEqual判斷是相等的