Commit 3047b0d5 authored by Shen Chang's avatar Shen Chang

refactor(Add < KeepAlive > Components and delete keepAlive higher-order components):

parent 3e12c088
...@@ -6,7 +6,7 @@ import { ...@@ -6,7 +6,7 @@ import {
Link, Link,
BrowserRouter as Router, BrowserRouter as Router,
} from 'react-router-dom'; } from 'react-router-dom';
import {Provider} from '../../es'; import {Provider, KeepAlive} from '../../es';
import A from './views/A'; import A from './views/A';
import B from './views/B'; import B from './views/B';
import C from './views/C'; import C from './views/C';
...@@ -58,18 +58,24 @@ class App extends React.Component { ...@@ -58,18 +58,24 @@ class App extends React.Component {
<Route <Route
path="/a" path="/a"
render={() => ( render={() => (
<React.Fragment> <KeepAlive key="A" disabled={!toggle}>
<A keepAlive={toggle} /> <A />
</React.Fragment> </KeepAlive>
)} )}
/> />
<Route <Route
path="/b" path="/b"
render={() => <B />} render={() => (
<B />
)}
/> />
<Route <Route
path="/c" path="/c"
render={() => <C />} render={() => (
<KeepAlive key="C">
<C />
</KeepAlive>
)}
/> />
</Switch> </Switch>
</div> </div>
......
import React from 'react'; import React from 'react';
import {keepAlive, bindLifecycle} from '../../../es'; import {bindLifecycle} from '../../../es';
@bindLifecycle @bindLifecycle
class Content extends React.Component { class Content extends React.Component {
...@@ -40,7 +40,7 @@ class Content extends React.Component { ...@@ -40,7 +40,7 @@ class Content extends React.Component {
} }
} }
@keepAlive() @bindLifecycle
class Test extends React.Component { class Test extends React.Component {
state = { state = {
index: 0, index: 0,
......
import React from 'react'; import React from 'react';
import {keepAlive, bindLifecycle} from '../../../es'; import {bindLifecycle} from '../../../es';
@keepAlive() @bindLifecycle
class B extends React.Component { class B extends React.Component {
componentWillMount() { componentWillMount() {
console.log('B componentWillMount'); console.log('B componentWillMount');
......
import React from 'react'; import React from 'react';
import {keepAlive} from '../../../es'; import {bindLifecycle} from '../../../es';
@bindLifecycle
class C extends React.Component { class C extends React.Component {
componentWillMount() { componentWillMount() {
console.log('C componentWillMount'); console.log('C componentWillMount');
...@@ -38,4 +39,4 @@ class C extends React.Component { ...@@ -38,4 +39,4 @@ class C extends React.Component {
} }
} }
export default keepAlive()(C); export default C;
{ {
"name": "react-keep-alive", "name": "react-keep-alive",
"version": "0.2.2", "version": "0.3.0",
"description": "Package will allow components to maintain their status, to avoid repeated re-rendering.", "description": "Package will allow components to maintain their status, to avoid repeated re-rendering.",
"author": "Shen Chang", "author": "Shen Chang",
"homepage": "https://github.com/Sam618/react-keep-alive", "homepage": "https://github.com/Sam618/react-keep-alive",
......
...@@ -3,7 +3,6 @@ import Comment from './Comment'; ...@@ -3,7 +3,6 @@ import Comment from './Comment';
import {LIFECYCLE, ICache, ICacheItem} from './Provider'; import {LIFECYCLE, ICache, ICacheItem} from './Provider';
import {warn} from '../utils/debug'; import {warn} from '../utils/debug';
import findDOMNodeByFiberNode from '../utils/findDOMNodeByFiberNode'; import findDOMNodeByFiberNode from '../utils/findDOMNodeByFiberNode';
import createUniqueIdentification from '../utils/createUniqueIdentification';
interface IConsumerProps { interface IConsumerProps {
children: React.ReactNode; children: React.ReactNode;
...@@ -19,9 +18,6 @@ class Consumer extends React.PureComponent<IConsumerProps> { ...@@ -19,9 +18,6 @@ class Consumer extends React.PureComponent<IConsumerProps> {
private identification: string = this.props.identification; private identification: string = this.props.identification;
// This attribute is designed to prevent duplicates of the identification of KeepAlive components.
private key: string = createUniqueIdentification();
constructor(props: IConsumerProps, ...args: any) { constructor(props: IConsumerProps, ...args: any) {
super(props, ...args); super(props, ...args);
const {cache, setCache, children} = props; const {cache, setCache, children} = props;
...@@ -43,7 +39,6 @@ class Consumer extends React.PureComponent<IConsumerProps> { ...@@ -43,7 +39,6 @@ class Consumer extends React.PureComponent<IConsumerProps> {
children, children,
keepAlive, keepAlive,
lifecycle: LIFECYCLE.MOUNTED, lifecycle: LIFECYCLE.MOUNTED,
key: this.key,
renderElement: this.renderElement, renderElement: this.renderElement,
activated: true, activated: true,
}); });
......
import React from 'react';
import noop from '../utils/noop';
import keepAlive, {IKeepAliveComponentProps} from '../utils/keepAlive';
export const keepAliveDisplayName = '$$KeepAlive';
interface IKeepAliveProps extends IKeepAliveComponentProps {
key: string;
onActivate?: () => void;
onUnactivate?: () => void;
}
class KeepAlive extends React.PureComponent<IKeepAliveProps> {
public displayName = keepAliveDisplayName;
public static defaultProps = {
onActivate: noop,
onUnactivate: noop,
};
public componentDidActivate() {
(this.props as any).onActivate();
}
public componentWillUnactivate() {
(this.props as any).onUnactivate();
}
public render() {
return this.props.children;
}
}
export default keepAlive(KeepAlive) as React.ComponentClass<IKeepAliveProps>;
...@@ -7,7 +7,7 @@ import {warn} from '../utils/debug'; ...@@ -7,7 +7,7 @@ import {warn} from '../utils/debug';
import createUniqueIdentification from '../utils/createUniqueIdentification'; import createUniqueIdentification from '../utils/createUniqueIdentification';
import createStoreElement from '../utils/createStoreElement'; import createStoreElement from '../utils/createStoreElement';
export const keepAliveProviderTypeName = 'KeepAliveProvider'; export const keepAliveProviderTypeName = '$$KeepAliveProvider';
export const START_MOUNTING_DOM = 'startMountingDOM'; export const START_MOUNTING_DOM = 'startMountingDOM';
export enum LIFECYCLE { export enum LIFECYCLE {
...@@ -20,7 +20,6 @@ export interface ICacheItem { ...@@ -20,7 +20,6 @@ export interface ICacheItem {
children: React.ReactNode; children: React.ReactNode;
keepAlive: boolean; keepAlive: boolean;
lifecycle: LIFECYCLE; lifecycle: LIFECYCLE;
key?: string | null;
renderElement?: HTMLElement; renderElement?: HTMLElement;
activated?: boolean; activated?: boolean;
ifStillActivate?: boolean; ifStillActivate?: boolean;
...@@ -87,10 +86,6 @@ export default class KeepAliveProvider extends React.PureComponent<IKeepAlivePro ...@@ -87,10 +86,6 @@ export default class KeepAliveProvider extends React.PureComponent<IKeepAlivePro
public setCache = (identification: string, value: ICacheItem) => { public setCache = (identification: string, value: ICacheItem) => {
const {cache, keys} = this; const {cache, keys} = this;
const currentCache = cache[identification]; const currentCache = cache[identification];
const key = currentCache && currentCache.key;
if (key && value.key && key !== (value.key as unknown)) {
warn('[React Keep Alive] Cached components have duplicates.');
}
if (!currentCache) { if (!currentCache) {
keys.push(identification); keys.push(identification);
} }
...@@ -101,6 +96,10 @@ export default class KeepAliveProvider extends React.PureComponent<IKeepAlivePro ...@@ -101,6 +96,10 @@ export default class KeepAliveProvider extends React.PureComponent<IKeepAlivePro
this.forceUpdate(); this.forceUpdate();
} }
public componentDidCatch() {
warn('[React Keep Alive] Cached components have duplicates. Please check the <KeepAlive> component of the key duplication!');
}
// private getMax = () => { // private getMax = () => {
// return this.props.max ? parseInt(this.props.max) : null; // return this.props.max ? parseInt(this.props.max) : null;
// } // }
...@@ -126,7 +125,6 @@ export default class KeepAliveProvider extends React.PureComponent<IKeepAlivePro ...@@ -126,7 +125,6 @@ export default class KeepAliveProvider extends React.PureComponent<IKeepAlivePro
const {cache} = this; const {cache} = this;
this.cache[identification] = { this.cache[identification] = {
...cache[identification], ...cache[identification],
key: null,
activated: false, activated: false,
lifecycle: LIFECYCLE.UNMOUNTED, lifecycle: LIFECYCLE.UNMOUNTED,
}; };
......
import Provider from './components/Provider'; import Provider from './components/Provider';
import keepAlive from './utils/keepAlive'; import KeepAlive from './components/KeepAlive';
import bindLifecycle from './utils/bindLifecycle'; import bindLifecycle from './utils/bindLifecycle';
export { export {
Provider, Provider,
keepAlive, KeepAlive,
bindLifecycle, bindLifecycle,
}; };
...@@ -5,7 +5,7 @@ import {COMMAND} from './keepAlive'; ...@@ -5,7 +5,7 @@ import {COMMAND} from './keepAlive';
import withIdentificationContextConsumer from './withIdentificationContextConsumer'; import withIdentificationContextConsumer from './withIdentificationContextConsumer';
import getDisplayName from './getDisplayName'; import getDisplayName from './getDisplayName';
export default function bindLifecycle<P = any>(Component: React.ComponentType<P>) { export default function bindLifecycle<P = any>(Component: React.ComponentClass<P>) {
const WrappedComponent = (Component as any).WrappedComponent || (Component as any).wrappedComponent || Component; const WrappedComponent = (Component as any).WrappedComponent || (Component as any).wrappedComponent || Component;
const { const {
...@@ -111,7 +111,7 @@ export default function bindLifecycle<P = any>(Component: React.ComponentType<P> ...@@ -111,7 +111,7 @@ export default function bindLifecycle<P = any>(Component: React.ComponentType<P>
: null : null
), ),
); );
const BindLifecycle = React.forwardRef((props, ref) => ( const BindLifecycle = React.forwardRef((props: P, ref) => (
<BindLifecycleHOC {...props} forwardRef={ref} /> <BindLifecycleHOC {...props} forwardRef={ref} />
)); ));
......
import React from 'react';
import {keepAliveProviderTypeName} from '../components/Provider';
import {keepAliveDisplayName} from './keepAlive';
export default function getContextIdentificationByFiberNode(fiberNode: any) {
let globalKey: React.Key | null = null;
let typeNames = '';
function getPathsByFiberNode(fiberNode: any) {
if (!fiberNode) {
return '';
}
const {
type,
key,
index,
} = fiberNode;
const typeName = type && type.displayName;
if (typeName === keepAliveProviderTypeName) {
return '';
}
const joinName: string = getPathsByFiberNode(fiberNode.return);
if (type && type.displayName && type.displayName.indexOf(keepAliveDisplayName) !== -1) {
if (!globalKey) {
globalKey = key;
}
}
typeNames += typeName;
return `${key || index}${joinName}`;
}
const paths = getPathsByFiberNode(fiberNode);
return {
paths,
globalKey,
typeNames,
};
}
import React from 'react'; import React from 'react';
export default function getDisplayName(Component: React.ComponentType) { export default function getDisplayName(Component: React.ComponentType) {
return Component.displayName || Component.name || null; return Component.displayName || Component.name || 'Component';
} }
import {WithKeepAliveContextConsumerDisplayName} from './withKeepAliveContextConsumer';
export default function getKeyByFiberNode(fiberNode: any): string | null {
if (!fiberNode) {
return null;
}
const {
key,
type,
} = fiberNode;
if (type.displayName && type.displayName.indexOf(WithKeepAliveContextConsumerDisplayName) !== -1) {
return key;
}
return getKeyByFiberNode(fiberNode.return);
}
This diff is collapsed.
...@@ -11,17 +11,19 @@ export interface IIdentificationContextProps { ...@@ -11,17 +11,19 @@ export interface IIdentificationContextProps {
isExisted: () => boolean; isExisted: () => boolean;
} }
export interface IIdentificationContextComponentProps { export interface IIdentificationContextConsumerComponentProps {
_identificationContextProps: IIdentificationContextProps; _identificationContextProps: IIdentificationContextProps;
} }
export default function withIdentificationContextConsumer<P = any>(Component: React.ComponentType<IIdentificationContextComponentProps & P>) { export const withIdentificationContextConsumerDisplayName = 'withIdentificationContextConsumer';
const NewComponent = (props: P) => (
export default function withIdentificationContextConsumer<P = any>(Component: React.ComponentType<IIdentificationContextConsumerComponentProps & P>) {
const WithIdentificationContextConsumer = (props: P) => (
<IdentificationContext.Consumer> <IdentificationContext.Consumer>
{(contextProps: IIdentificationContextProps) => <Component _identificationContextProps={contextProps} {...props} />} {(contextProps: IIdentificationContextProps) => <Component _identificationContextProps={contextProps} {...props} />}
</IdentificationContext.Consumer> </IdentificationContext.Consumer>
); );
NewComponent.displayName = `withIdentificationContextConsumer(${getDisplayName(Component)})`; WithIdentificationContextConsumer.displayName = `${withIdentificationContextConsumerDisplayName}(${getDisplayName(Component)})`;
return NewComponent; return WithIdentificationContextConsumer;
} }
...@@ -5,17 +5,19 @@ import getDisplayName from './getDisplayName'; ...@@ -5,17 +5,19 @@ import getDisplayName from './getDisplayName';
type IKeepAliveContextProps = IKeepAliveProviderImpl & IKeepAliveProviderProps; type IKeepAliveContextProps = IKeepAliveProviderImpl & IKeepAliveProviderProps;
export interface IKeepAliveContextComponentProps { export interface IKeepAliveContextConsumerComponentProps {
_keepAliveContextProps: IKeepAliveContextProps; _keepAliveContextProps: IKeepAliveContextProps;
} }
export default function withKeepAliveContextConsumer<P = any>(Component: React.ComponentType<IKeepAliveContextComponentProps & P>) { export const WithKeepAliveContextConsumerDisplayName = 'withKeepAliveContextConsumer';
const NewComponent = (props: P) => (
export default function withKeepAliveContextConsumer<P = any>(Component: React.ComponentType<IKeepAliveContextConsumerComponentProps & P>) {
const WithKeepAliveContextConsumer = (props: P) => (
<KeepAliveContext.Consumer> <KeepAliveContext.Consumer>
{(contextProps: IKeepAliveContextProps) => <Component _keepAliveContextProps={contextProps} {...props} />} {(contextProps: IKeepAliveContextProps) => <Component _keepAliveContextProps={contextProps} {...props} />}
</KeepAliveContext.Consumer> </KeepAliveContext.Consumer>
); );
NewComponent.displayName = `withKeepAliveContextConsumer(${getDisplayName(Component)})`; WithKeepAliveContextConsumer.displayName = `${WithKeepAliveContextConsumerDisplayName}(${getDisplayName(Component)})`;
return NewComponent; return WithKeepAliveContextConsumer;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment