/** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @flow * @format */ import {arrayEqual} from './collection'; import Hasher from './Hasher'; type CompareFunc = (a: Array, b: Array) => boolean; type KeySelector = (x: T) => U; const NOTHING = Symbol('nothing'); /** * Create a memoized version of the provided function that caches only the latest result. This is * especially useful for optimizing React component methods without having to worry about * maintaining state explicitly. For example: * * class MyComponent extends React.Component { * constructor(props) { * super(props); * this._computeSomethingExpensive = memoizeUntilChanged(this._computeSomethingExpensive); * } * _computeSomethingExpensive(x) { ... } * render() { * const thingToRender = this._computeSomethingExpensive(this.props.value); * return
{thingToRender}
; * } * } */ export default function memoizeUntilChanged( func: T, keySelector_?: KeySelector, compareKeys: CompareFunc = arrayEqual, ): T { let prevArgKeys; let prevResult = NOTHING; const keySelector: KeySelector = keySelector_ || createKeySelector(); // $FlowIssue: Flow can't express that we want the args to be the same type as the input func's. return function(...args) { const argKeys = args.map(keySelector); if (prevResult === NOTHING || !compareKeys(argKeys, prevArgKeys)) { prevArgKeys = argKeys; prevResult = func.apply(this, args); } return prevResult; }; } function createKeySelector(): KeySelector { const hasher: Hasher = new Hasher(); return x => hasher.getHash(x); }