import { Component , FunctionComponent , ComponentClass } from "react" ; import * as React from 'react' ; const hasOwnProperty = Object . prototype . hasOwnProperty ; /**
 * inlined Object.is polyfill to avoid requiring consumers ship their own
 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
 */ function is ( x , y ) { if ( x === y ) { return x !== 0 || y !== 0 || 1 / x === 1 / y ; } else { return x !== x && y !== y ; } } const duckKey = "duck" ; const storeKey = "store" ; /**
 * Performs equality by iterating through keys on an object and returning false
 * when any key has values which are not strictly equal between the arguments.
 * Returns true when the values of all keys are strictly equal.
 */ function shallowEqual ( objA , objB ) { if ( is ( objA , objB ) ) { return true ; } if ( typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null ) { return false ; } const keysA = Object . keys ( objA ) ; const keysB = Object . keys ( objB ) ; if ( keysA . length !== keysB . length ) { return false ; } const isDuckComponent = duckKey in objA && storeKey in objA && ( duckKey in objB && storeKey in objB ) ; for ( let i = 0 ; i < keysA . length ; i ++ ) { const key = keysA [ i ] ; if ( isDuckComponent && key === storeKey && is ( objA [ duckKey ] . selector ( objA [ storeKey ] ) , objB [ duckKey ] . selector ( objB [ storeKey ] ) ) ) { continue ; } if ( ! hasOwnProperty . call ( objB , key ) || ! is ( objA [ key ] , objB [ key ] ) ) { return false ; } } return true ; } export function shouldComponentUpdate ( instance , props , state ) { return ( ! shallowEqual ( instance . props , props ) || ! shallowEqual ( instance . state , state ) ) ; } function shouldComponentUpdateForReplace ( nextProps , nextState ) { return shouldComponentUpdate ( this , nextProps , nextState ) ; } /**
 * Make React Component Memorizeable.
 * If props.duck's local state unchange, ignore store change.
 */ export interface PurifyType { < P , F extends FunctionComponent < P > > ( component ) : F ; < P , C extends ComponentClass < P > > ( component ) : C ; < A > ( any ) : A ; } export const purify = function ( component ) { if ( typeof component . prototype ?. isReactComponent === "object" ) { const Cmp = component as ComponentClass < any > ; if ( Cmp . prototype . shouldComponentUpdate !== undefined ) { console . warn ( "purify() only use to decorate class dose not implement shouldComponentUpdate" ) ; } Cmp . prototype . shouldComponentUpdate = shouldComponentUpdateForReplace ; return Cmp ; } else { const statelessRender = component as FunctionComponent < any > ; if ( React . memo ) { return React . memo ( statelessRender , shallowEqual ) ; } class PureRender extends Component < any > { render ( ) { return statelessRender ( this . props ) ; } shouldComponentUpdate ( nextProps , nextState ) { return shouldComponentUpdate ( this , nextProps , nextState ) ; } } ( PureRender as any ) . displayName = statelessRender && statelessRender . name ; return PureRender ; } } ; /**
 * 优化Duck函数组件，使它在所属duck对应的state未变化时不重新渲染
 *
 * Make React stateless Component Memorizeable.
 * If props.duck's local state unchange, ignore store change.
 *
 * **仅支持react16 / Use only for react16**
 */ export function memo < T > ( func ) { return React . memo ( func , shallowEqual ) ; }