Skip to content

Commit d22c538

Browse files
committed
hooks order
1 parent 4580a09 commit d22c538

5 files changed

Lines changed: 241 additions & 1 deletion

File tree

src/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import "./App.css";
33
import examplesUseState1 from "./examples/use-state-1";
44
import examplesUseEffect1 from "./examples/use-effect-1";
55
import examplesUseRef1 from "./examples/use-ref-1";
6+
import examplesHooksOrder from "./examples/hooks-order";
67
import logo from "./logo.svg";
78
import ExampleBloc from "./commons/ExampleBloc";
89
import { IExample } from "./commons/types";
@@ -15,7 +16,8 @@ const App: React.FC = () => {
1516
let examples: IExample[] = ([] as IExample[])
1617
.concat(examplesUseState1)
1718
.concat(examplesUseEffect1)
18-
.concat(examplesUseRef1);
19+
.concat(examplesUseRef1)
20+
.concat(examplesHooksOrder);
1921

2022
return (
2123
<div className="App">
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React from "react";
2+
import ActionButton from "../../commons/ActionButton";
3+
import { useLog } from "../../commons/ExampleBloc";
4+
5+
const ExampleHooksOrder101 = () => {
6+
const log = useLog();
7+
8+
const [order, setOrder] = React.useState<boolean>(false);
9+
10+
let number: number, setNumber: (value: number) => void;
11+
let string: string, setString: (value: string) => void;
12+
if (order) {
13+
// eslint-disable-next-line react-hooks/rules-of-hooks
14+
const n = React.useState<number>(0);
15+
number = n[0];
16+
setNumber = n[1];
17+
// eslint-disable-next-line react-hooks/rules-of-hooks
18+
const s = React.useState<string>("");
19+
string = s[0];
20+
setString = s[1];
21+
} else {
22+
// eslint-disable-next-line react-hooks/rules-of-hooks
23+
const s = React.useState<string>("");
24+
string = s[0];
25+
setString = s[1];
26+
// eslint-disable-next-line react-hooks/rules-of-hooks
27+
const n = React.useState<number>(0);
28+
number = n[0];
29+
setNumber = n[1];
30+
}
31+
32+
log("virtual-render", { order, number, string });
33+
34+
return (
35+
<>
36+
<pre>{JSON.stringify({ order, number, string }, null, 2)}</pre>
37+
<ul>
38+
<li>
39+
<ActionButton
40+
label="Do nothing state-wise"
41+
onClick={() => {
42+
/* NOOP */
43+
}}
44+
/>
45+
</li>
46+
<li>
47+
<ActionButton
48+
label="Randomize number"
49+
onClick={() => {
50+
setNumber(Math.round(Math.random() * 1000));
51+
}}
52+
/>
53+
</li>
54+
<li>
55+
<ActionButton
56+
label="Randomize string"
57+
onClick={() => {
58+
setString(
59+
Math.random()
60+
.toString(36)
61+
.substr(2, 5)
62+
);
63+
}}
64+
/>
65+
</li>
66+
<li>
67+
<ActionButton
68+
label="Switch order"
69+
onClick={() => {
70+
setOrder(!order);
71+
}}
72+
/>
73+
</li>
74+
</ul>
75+
</>
76+
);
77+
};
78+
79+
export default ExampleHooksOrder101;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import React from "react";
2+
import ActionButton from "../../commons/ActionButton";
3+
import { useLog } from "../../commons/ExampleBloc";
4+
5+
const ExampleUseState102 = () => {
6+
const log = useLog();
7+
8+
const [numberState, setNumberState] = React.useState<number>(0);
9+
const [stringState, setStringState] = React.useState<string>("");
10+
const [objectState, setObjectState] = React.useState<{ insideVal: string }>({
11+
insideVal: ""
12+
});
13+
log("virtual-render", { numberState, stringState, objectState });
14+
15+
return (
16+
<>
17+
<pre>
18+
{JSON.stringify({ numberState, stringState, objectState }, null, 2)}
19+
</pre>
20+
21+
<ul>
22+
<li>
23+
<ActionButton
24+
label="Update numberState"
25+
onClick={() => {
26+
const s = Number.parseFloat(prompt("Value?") || "");
27+
setNumberState(s);
28+
}}
29+
/>
30+
</li>
31+
<li>
32+
<ActionButton
33+
label="Update stringState"
34+
onClick={() => {
35+
const s = prompt("Value?") || "";
36+
setStringState(s);
37+
}}
38+
/>
39+
</li>
40+
<li>
41+
<ActionButton
42+
label="Update objectState"
43+
onClick={() => {
44+
const s = prompt("Value?") || "";
45+
setObjectState({ insideVal: s });
46+
}}
47+
/>
48+
</li>
49+
<li>
50+
<ActionButton
51+
label="Do something stupid v1"
52+
onClick={() => {
53+
const s = prompt("Value?") || "";
54+
objectState.insideVal = s;
55+
}}
56+
/>
57+
</li>
58+
<li>
59+
<ActionButton
60+
label="Do something stupid v2"
61+
onClick={() => {
62+
const s = prompt("Value?") || "";
63+
objectState.insideVal = s;
64+
setObjectState(objectState);
65+
}}
66+
/>
67+
</li>
68+
</ul>
69+
</>
70+
);
71+
};
72+
73+
export default ExampleUseState102;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React from "react";
2+
import ActionButton from "../../commons/ActionButton";
3+
import { useLog } from "../../commons/ExampleBloc";
4+
5+
const ExampleUseState103 = () => {
6+
const log = useLog();
7+
8+
const [counter, setCounter] = React.useState<number>(0);
9+
const [counterDoubled, setcounterDoubled] = React.useState<number>(0);
10+
11+
log("virtual-render", { counter, counterDoubled });
12+
13+
return (
14+
<>
15+
<pre>{JSON.stringify({ counter, counterDoubled }, null, 2)}</pre>
16+
<ul>
17+
<li>
18+
<ActionButton
19+
label="Reset"
20+
onClick={() => {
21+
setCounter(0);
22+
setcounterDoubled(0);
23+
}}
24+
/>
25+
</li>
26+
<li>
27+
<ActionButton
28+
label="Increment v1"
29+
onClick={() => {
30+
log("Before increment", { counter, counterDoubled });
31+
setCounter(counter + 1);
32+
setcounterDoubled(counter * 2);
33+
log("After increment", { counter, counterDoubled });
34+
}}
35+
/>
36+
</li>
37+
<li>
38+
<ActionButton
39+
label="Increment v2"
40+
onClick={() => {
41+
log("Before increment", { counter, counterDoubled });
42+
const newCounter = counter + 1;
43+
setCounter(newCounter);
44+
setcounterDoubled(newCounter * 2);
45+
log("After increment", { counter, counterDoubled });
46+
}}
47+
/>
48+
</li>
49+
</ul>
50+
</>
51+
);
52+
};
53+
54+
export default ExampleUseState103;

src/examples/hooks-order/index.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* eslint import/no-webpack-loader-syntax: off */
2+
import ExampleHooksOrder101Code from "!raw-loader!./ExampleHooksOrder101";
3+
4+
import React from "react";
5+
import { IExample } from "../../commons/types";
6+
import ExampleHooksOrder101 from "./ExampleHooksOrder101";
7+
8+
const examples: IExample[] = [
9+
{
10+
title: "hooks-order 101",
11+
Component: ExampleHooksOrder101,
12+
code: ExampleHooksOrder101Code,
13+
preface: (
14+
<>
15+
Obviously never do that, and the eslint rule{" "}
16+
<strong>react-hooks/rules-of-hooks</strong> is here to protect you!
17+
<br />
18+
Play a little with this example and try to guess what trick React uses
19+
to remember which state is which.
20+
</>
21+
),
22+
explanation: (
23+
<>
24+
As you were able to guess, React uses the call order of the hooks to
25+
remember which is which. Therefore, hooks should never be called inside
26+
a condition or a loop, and always in the component top level.
27+
</>
28+
)
29+
}
30+
];
31+
32+
export default examples;

0 commit comments

Comments
 (0)