mirror of
https://github.com/bendtherules/react-hooks-with-class.git
synced 2026-08-18 22:03:11 +00:00
Add alternative to useEffect
This commit is contained in:
+156
@@ -0,0 +1,156 @@
|
|||||||
|
import React, { Component } from "react";
|
||||||
|
|
||||||
|
import "./App.css";
|
||||||
|
|
||||||
|
export default class App extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this._internal = {
|
||||||
|
effects: [], // array of {asyncFn, dependencyArrayFnOptional, oldDependencyArray, unregisterFn}
|
||||||
|
};
|
||||||
|
|
||||||
|
([this.getCount, this.setCount] = this.useState('count', 0));
|
||||||
|
|
||||||
|
({ getData: this.getData, getLoading: this.getLoading } = this.useFetch("https://api.randomuser.me/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
useState(key, initialValue) {
|
||||||
|
this.state = {
|
||||||
|
...this.state,
|
||||||
|
[key]: initialValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
return ([
|
||||||
|
// get function
|
||||||
|
() => {
|
||||||
|
return this.state[key];
|
||||||
|
},
|
||||||
|
|
||||||
|
// set function
|
||||||
|
(newValue) => {
|
||||||
|
return this.setState({
|
||||||
|
[key]: newValue,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(asyncFn, dependencyArrayFnOptional = undefined) {
|
||||||
|
this._internal.effects.push({
|
||||||
|
asyncFn,
|
||||||
|
dependencyArrayFnOptional,
|
||||||
|
oldDependencyArray: undefined,
|
||||||
|
unregisterFn: undefined,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this._internal.effects.forEach((eachEffect) => {
|
||||||
|
const {
|
||||||
|
asyncFn,
|
||||||
|
dependencyArrayFnOptional,
|
||||||
|
// oldDependencyArray,
|
||||||
|
// unregisterFn,
|
||||||
|
} = eachEffect;
|
||||||
|
|
||||||
|
|
||||||
|
let newDependencyArray = undefined;
|
||||||
|
if (dependencyArrayFnOptional && dependencyArrayFnOptional.call) {
|
||||||
|
newDependencyArray = dependencyArrayFnOptional.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
eachEffect.oldDependencyArray = newDependencyArray;
|
||||||
|
|
||||||
|
Promise.resolve(asyncFn.call(this))
|
||||||
|
.then((newUnregisterFn) => {
|
||||||
|
eachEffect.unregisterFn = newUnregisterFn;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static didDependencyArrayUpdate(oldDependencyArray, newDependencyArray) {
|
||||||
|
if (
|
||||||
|
(!Array.isArray(oldDependencyArray) || !Array.isArray(newDependencyArray)) ||
|
||||||
|
(oldDependencyArray.length !== newDependencyArray.length)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return oldDependencyArray.some((_, index) => oldDependencyArray[index] !== newDependencyArray[index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
this._internal.effects.forEach((eachEffect) => {
|
||||||
|
const {
|
||||||
|
asyncFn,
|
||||||
|
dependencyArrayFnOptional,
|
||||||
|
oldDependencyArray,
|
||||||
|
unregisterFn,
|
||||||
|
} = eachEffect;
|
||||||
|
|
||||||
|
let newDependencyArray = undefined;
|
||||||
|
if (dependencyArrayFnOptional && dependencyArrayFnOptional.call) {
|
||||||
|
newDependencyArray = dependencyArrayFnOptional.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (App.didDependencyArrayUpdate(oldDependencyArray, newDependencyArray)) {
|
||||||
|
eachEffect.oldDependencyArray = newDependencyArray;
|
||||||
|
|
||||||
|
if (unregisterFn && unregisterFn.call) {
|
||||||
|
unregisterFn.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.resolve(asyncFn.call(this))
|
||||||
|
.then((newUnregisterFn) => {
|
||||||
|
eachEffect.unregisterFn = newUnregisterFn;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this._internal.effects.forEach((eachEffect) => {
|
||||||
|
const {
|
||||||
|
unregisterFn,
|
||||||
|
} = eachEffect;
|
||||||
|
|
||||||
|
if (unregisterFn && unregisterFn.call) {
|
||||||
|
unregisterFn.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
delete this._internal.effects;
|
||||||
|
}
|
||||||
|
|
||||||
|
useFetch(url) {
|
||||||
|
const [getData, setData] = this.useState("data", null);
|
||||||
|
const [getLoading, setLoading] = this.useState("loading", true);
|
||||||
|
|
||||||
|
// Similar to componentDidMount and componentDidUpdate:
|
||||||
|
this.useEffect(async () => {
|
||||||
|
const response = await fetch(url);
|
||||||
|
const data = await response.json();
|
||||||
|
const [item] = data.results;
|
||||||
|
// TODO: If possible, batch these two updates
|
||||||
|
setData(item);
|
||||||
|
setLoading(false);
|
||||||
|
}, () => ([this.getCount()]));
|
||||||
|
|
||||||
|
return { getData, getLoading };
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const count = this.getCount();
|
||||||
|
const data = this.getData();
|
||||||
|
const loading = this.getLoading();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>You clicked {count} times</p>
|
||||||
|
<button onClick={() => this.setCount(count + 1)}>Click me</button>
|
||||||
|
{loading ? <div>...loading</div> : <div>{data.name.first}</div>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import App from "./App";
|
import App from "./App2";
|
||||||
import * as serviceWorker from "./serviceWorker";
|
import * as serviceWorker from "./serviceWorker";
|
||||||
|
|
||||||
ReactDOM.render(<App />, document.getElementById("root"));
|
ReactDOM.render(<App />, document.getElementById("root"));
|
||||||
|
|||||||
Reference in New Issue
Block a user