Commit 46c0028d authored by Shen Chang's avatar Shen Chang

refactor: Remove the componentDidActivate and componentWillUnmount lifecycles,...

refactor: Remove the componentDidActivate and componentWillUnmount lifecycles, Remove the <KeepAlive
parent 56d781e6
import React from 'react';
import React, {useState} from 'react';
import ReactDOM from 'react-dom';
import {
Switch,
......@@ -11,47 +11,24 @@ import A from './views/A';
import B from './views/B';
import C from './views/C';
class App extends React.Component {
state = {
toggle: true,
};
handleClick = () => {
this.setState(({toggle}) => ({
toggle: !toggle,
}));
}
handleClickB = () => {
this.setState({
toggle: true,
});
}
handleClickC = () => {
this.setState({
toggle: false,
});
}
render() {
const {toggle} = this.state;
function App() {
const [toggle, setToggle] = useState(true);
return (
<div>
<ul>
<li>
<Link to="/a">a</Link>
</li>
<li onClick={this.handleClickB}>
<li onClick={() => setToggle(true)}>
<Link to="/b">b</Link>
</li>
<li onClick={this.handleClickC}>
<li onClick={() => setToggle(false)}>
<Link to="/c">c</Link>
</li>
</ul>
<div>
<button onClick={this.handleClick}>toggle({toggle.toString()})</button>
<button onClick={() => setToggle(!toggle)}>toggle({toggle.toString()})</button>
</div>
<Switch>
......@@ -81,7 +58,6 @@ class App extends React.Component {
</Switch>
</div>
);
}
}
ReactDOM.render(
......
import React from 'react';
import {Provider, KeepAlive} from '../../../es';
import React, {useState} from 'react';
import {useKeepAliveEffect} from '../../../es';
class Content extends React.Component {
componentWillMount() {
console.log('A Content componentWillMount');
}
function Test() {
const [index, setIndex] = useState(0);
useKeepAliveEffect(() => {
console.log('activated');
componentDidMount() {
console.log('A Content componentDidMount');
}
componentDidActivate() {
console.log('A Content componentDidActivate');
}
componentWillUpdate() {
console.log('A Content componentWillUpdate');
}
componentDidUpdate() {
console.log('A Content componentDidUpdate');
}
componentWillUnactivate() {
console.log('A Content componentWillUnactivate');
}
componentWillUnmount() {
console.log('A Content componentWillUnmount');
}
render() {
console.log('A Content render');
console.log(this);
return (
<div>This is a content.</div>
);
}
}
class Test extends React.Component {
state = {
index: 0,
return () => {
console.log('unactivated');
};
componentWillMount() {
console.log('A componentWillMount');
}
componentDidMount() {
console.log('A componentDidMount');
}
componentDidActivate() {
console.log('A componentDidActivate');
}
componentWillUpdate() {
console.log('A componentWillUpdate');
}
componentDidUpdate() {
console.log('A componentDidUpdate');
}
componentWillUnactivate() {
console.log('A componentWillUnactivate');
}
componentWillUnmount() {
console.log('A componentWillUnmount');
}
handleClick = () => {
this.setState(({index}) => ({index: ++index}));
};
render() {
console.log('A render');
});
return (
<div>
<div>This is a.</div>
<button onClick={this.handleClick}>click me({this.state.index})</button>
{
this.state.index % 2 &&
<Provider>
<KeepAlive key="111">
<Content />
</KeepAlive>
</Provider>
}
<button onClick={() => setIndex(index + 1)}>click me({index})</button>
</div>
);
}
}
export default Test;
This diff is collapsed.
{
"name": "react-keep-alive",
"version": "0.4.3",
"version": "1.0.0-alpha.0",
"description": "Package will allow components to maintain their status, to avoid repeated re-rendering.",
"author": "Shen Chang",
"homepage": "https://github.com/Sam618/react-keep-alive",
"keywords": [
"react",
"keep-alive"
"react-router",
"keep-alive",
"cache"
],
"repository": {
"type": "git",
......@@ -57,9 +59,9 @@
"html-webpack-plugin": "^3.2.0",
"husky": "^1.3.1",
"jest": "^24.1.0",
"react": "^16.3.0",
"react-dom": "^16.3.0",
"react-router-dom": "^4.3.1",
"react": "^16.8.5",
"react-dom": "^16.8.5",
"react-router-dom": "^5.0.0",
"rimraf": "^2.6.3",
"ts-jest": "^23.10.5",
"typescript": "^3.3.1",
......
import React from 'react';
import noop from '../utils/noop';
import keepAlive, {IKeepAliveComponentProps} from '../utils/keepAlive';
import {START_MOUNTING_DOM, LIFECYCLE} from './Provider';
import keepAlive, {COMMAND} from '../utils/keepAliveDecorator';
import changePositionByComment from '../utils/changePositionByComment';
export const keepAliveDisplayName = '$$KeepAlive';
interface IKeepAliveProps extends IKeepAliveComponentProps {
interface IKeepAliveProps {
key: string;
onActivate?: () => void;
onUnactivate?: () => void;
disabled?: boolean;
_container: any;
}
class KeepAlive extends React.PureComponent<IKeepAliveProps> {
public displayName = keepAliveDisplayName;
private bindUnmount: (() => void) | null = null;
public static defaultProps = {
onActivate: noop,
onUnactivate: noop,
public componentDidMount() {
const {
_container,
} = this.props;
const {
notNeedActivate,
identification,
eventEmitter,
} = _container;
notNeedActivate();
const cb = () => {
this.mount();
this.listen();
eventEmitter.off([identification, START_MOUNTING_DOM], cb);
};
eventEmitter.on([identification, START_MOUNTING_DOM], cb);
}
public componentDidUpdate() {
const {
_container,
} = this.props;
const {
notNeedActivate,
isNeedActivate,
} = _container;
if (isNeedActivate()) {
notNeedActivate();
this.mount();
this.listen();
}
}
public componentWillUnmount() {
this.unmount();
this.unlisten();
}
private mount() {
const {
_container: {
cache,
identification,
storeElement,
setLifecycle,
},
} = this.props;
const {renderElement} = cache[identification];
setLifecycle(LIFECYCLE.UPDATING);
changePositionByComment(identification, renderElement, storeElement);
}
private unmount() {
const {
_container: {
identification,
storeElement,
cache,
setLifecycle,
},
} = this.props;
const {renderElement, ifStillActivate, reactivate} = cache[identification];
setLifecycle(LIFECYCLE.UNMOUNTED);
changePositionByComment(identification, storeElement, renderElement);
if (ifStillActivate) {
reactivate();
}
}
public componentDidActivate() {
(this.props as any).onActivate();
private listen() {
const {
_container: {
identification,
eventEmitter,
},
} = this.props;
eventEmitter.on(
[identification, COMMAND.CURRENT_UNMOUNT],
this.bindUnmount = this.componentWillUnmount.bind(this),
);
}
public componentWillUnactivate() {
(this.props as any).onUnactivate();
private unlisten() {
const {
_container: {
identification,
eventEmitter,
},
} = this.props;
eventEmitter.off([identification, COMMAND.CURRENT_UNMOUNT], this.bindUnmount);
}
public render() {
......
......@@ -119,6 +119,7 @@ export default class KeepAliveProvider extends React.PureComponent<IKeepAlivePro
providerIdentification,
isExisted,
setCache,
existed,
unactivate,
storeElement,
eventEmitter,
......@@ -132,6 +133,8 @@ export default class KeepAliveProvider extends React.PureComponent<IKeepAlivePro
<KeepAliveContext.Provider
value={{
cache,
keys,
existed,
providerIdentification,
isExisted,
setCache,
......
import React from 'react';
const WithKeepAliveContext = React.createContext({});
export interface IIdentificationContextProps {
identification: string;
eventEmitter: any;
keepAlive: boolean;
getLifecycle: () => number;
isExisted: () => boolean;
}
const WithKeepAliveContext = React.createContext<IIdentificationContextProps>({} as any);
export default WithKeepAliveContext;
import React from 'react';
import {IKeepAliveProviderImpl, IKeepAliveProviderProps} from '../components/Provider';
const KeepAliveContext = React.createContext({});
export type IKeepAliveContextProps = IKeepAliveProviderImpl & IKeepAliveProviderProps;
const KeepAliveContext = React.createContext<IKeepAliveContextProps>({} as any);
export default KeepAliveContext;
import Provider from './components/Provider';
import KeepAlive from './components/KeepAlive';
import bindLifecycle from './utils/bindLifecycle';
import useKeepAliveEffect from './utils/useKeepAliveEffect';
export {
Provider,
KeepAlive,
bindLifecycle,
useKeepAliveEffect,
};
......@@ -2,7 +2,7 @@ import React from 'react';
import hoistNonReactStatics from 'hoist-non-react-statics';
import noop from './noop';
import {warn} from './debug';
import {COMMAND} from './keepAlive';
import {COMMAND} from './keepAliveDecorator';
import withIdentificationContextConsumer from './withIdentificationContextConsumer';
import getDisplayName from './getDisplayName';
......@@ -12,8 +12,6 @@ export default function bindLifecycle<P = any>(Component: React.ComponentClass<P
const {
componentDidMount = noop,
componentDidUpdate = noop,
componentDidActivate = noop,
componentWillUnactivate = noop,
componentWillUnmount = noop,
} = WrappedComponent.prototype;
......@@ -24,25 +22,12 @@ export default function bindLifecycle<P = any>(Component: React.ComponentClass<P
_container: {
identification,
eventEmitter,
activated,
},
keepAlive,
} = this.props;
// Determine whether to execute the componentDidActivate life cycle of the current component based on the activation state of the KeepAlive components
if (!activated && keepAlive !== false) {
componentDidActivate.call(this);
}
eventEmitter.on(
[identification, COMMAND.ACTIVATE],
this._bindActivate = () => this._needActivate = true,
true,
);
eventEmitter.on(
[identification, COMMAND.UNACTIVATE],
this._bindUnactivate = () => {
componentWillUnactivate.call(this);
this._unmounted = false;
},
eventEmitter.on(
[identification, COMMAND.MOUNT],
this._bindMount = () => this._needActivate = true,
true,
);
eventEmitter.on(
......@@ -54,11 +39,13 @@ export default function bindLifecycle<P = any>(Component: React.ComponentClass<P
true,
);
};
WrappedComponent.prototype.componentDidUpdate = function () {
componentDidUpdate.call(this);
WrappedComponent.prototype.componentDidUpdate = function (...args: any) {
if (this._needActivate) {
this._needActivate = false;
componentDidActivate.call(this);
this._unmounted = false;
componentDidMount.call(this);
} else {
componentDidUpdate.apply(this, args);
}
};
WrappedComponent.prototype.componentWillUnmount = function () {
......@@ -72,12 +59,8 @@ export default function bindLifecycle<P = any>(Component: React.ComponentClass<P
},
} = this.props;
eventEmitter.off(
[identification, COMMAND.ACTIVATE],
this._bindActivate,
);
eventEmitter.off(
[identification, COMMAND.UNACTIVATE],
this._bindUnactivate,
[identification, COMMAND.MOUNT],
this._bindMount,
);
eventEmitter.off(
[identification, COMMAND.UNMOUNT],
......@@ -91,8 +74,6 @@ export default function bindLifecycle<P = any>(Component: React.ComponentClass<P
_identificationContextProps: {
identification,
eventEmitter,
activated,
keepAlive,
},
...wrapperProps
}) => {
......@@ -107,8 +88,6 @@ export default function bindLifecycle<P = any>(Component: React.ComponentClass<P
_container={{
identification,
eventEmitter,
activated,
keepAlive,
}}
/>
);
......
import React, {useEffect, useContext} from 'react';
import {warn} from './debug';
import {COMMAND} from './keepAliveDecorator';
import IdentificationContext, {IIdentificationContextProps} from '../contexts/IdentificationContext';
export default function useKeepAliveEffect(effect: React.EffectCallback) {
if (!useEffect) {
warn('[React Keep Alive] useKeepAlive API requires react 16.8 or later.');
}
const {
eventEmitter,
identification,
} = useContext<IIdentificationContextProps>(IdentificationContext);
useEffect(() => {
let bindMount: (() => void) | null = null;
let bindUnmount: (() => void) | null = null;
let effectResult = effect();
let unmounted = false;
eventEmitter.on(
[identification, COMMAND.MOUNT],
bindMount = () => {
effectResult = effect();
unmounted = false;
},
true,
);
eventEmitter.on(
[identification, COMMAND.UNMOUNT],
bindUnmount = () => {
if (effectResult) {
effectResult();
unmounted = true;
}
},
true,
);
return () => {
if (effectResult && !unmounted) {
effectResult();
}
eventEmitter.off(
[identification, COMMAND.MOUNT],
bindMount,
);
eventEmitter.off(
[identification, COMMAND.UNMOUNT],
bindUnmount,
);
};
}, []);
}
import React from 'react';
import IdentificationContext from '../contexts/IdentificationContext';
import IdentificationContext, {IIdentificationContextProps} from '../contexts/IdentificationContext';
import getDisplayName from './getDisplayName';
export interface IIdentificationContextProps {
identification: string;
eventEmitter: any;
keepAlive: boolean;
activated: boolean;
getLifecycle: () => number;
isExisted: () => boolean;
}
export interface IIdentificationContextConsumerComponentProps {
_identificationContextProps: IIdentificationContextProps;
}
......
import React from 'react';
import {IKeepAliveProviderImpl, IKeepAliveProviderProps} from '../components/Provider';
import KeepAliveContext from '../contexts/KeepAliveContext';
import KeepAliveContext, {IKeepAliveContextProps} from '../contexts/KeepAliveContext';
import getDisplayName from './getDisplayName';
type IKeepAliveContextProps = IKeepAliveProviderImpl & IKeepAliveProviderProps;
export interface IKeepAliveContextConsumerComponentProps {
_keepAliveContextProps: IKeepAliveContextProps;
}
......
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