Reputation: 23
I was following along a presentation of Ryan florence (creator of remix and ReactTraining.com). There he was demistifying useState hook, by making one of his own.
I followed along the procedure, and implemented this in a component.
import React from 'react'
import ReactDOM from 'react-dom';
function MadeUseStateMyself() {
const [minutes,setMinutes] = useState(5)
const [error,setError] = useState(null)
const handleAdd = () => {
if(minutes<9){
setMinutes(minutes+1)
setError(null)
}
else{
setError('Less than 10 please')
}
}
const handleSubStract = () => {
if(minutes>0){
setMinutes(minutes-1)
setError(null)
}
else{
setError('More than 0 please')
}
}
return (
<React.Fragment>
<button onClick={handleSubStract} > - </button>
<p>{minutes}</p>
<button onClick={handleAdd} > + </button>
{error && <div>{error}</div>}
</React.Fragment>
)
}
const states = []
let calls = -1
const useState = def => {
const callId = ++calls
if(states[callId]) {
return states[callId]
}
const setDef = newV => {
states[callId][0] = newV
reRender()
}
const state = [def,setDef]
states.push(state)
return state
}
function reRender(){
calls = -1
ReactDOM.render(<MadeUseStateMyself/>,document.getElementById('root'))
}
export default MadeUseStateMyself
Here I noticed a really peculiar behavior, that is, whenever I use React.StrictMode wrapping my entire component, the state doesnt change after the first function call(In this case, I implemented an incremental and a decremental button which changes the state of one singular integer state.)
This problem doesnt rise if I get rid of the React.StrictMode wrapper.
Here is a CodeSandbox
Reading the StrictMode docs , one of my assumptions is that as in strictmode, function component bodies are invoked twice, it loses its first state during the second function call, thus losing the first change of state.
Am I even close?
Upvotes: 2
Views: 1021
Reputation: 202618
I had to watch about 13 minutes into the video to spot the first difference between your code and that in the demo. The presenter said to immediately manually invoke the custom reRender
function to do the initial render. It's from here I noticed that you were rendering your app twice. MadeUseStateMyself
is rendered once in the custom reRender
function and is also exported and rendered again into the DOM in the index.js
file.
You've effectively two instances of your MadeUseStateMyself
component rendered as a React stomping on each other.
If you take your code and immediately invoke reRender
, and also completely remove the index.js
rendering code, while also wrapping MadeUseStateMyself
in a React.StrictMode
component, you'll see it has no issues rendering and updating.
MadeUseStateMyself
import React from "react";
import ReactDOM from "react-dom";
const states = [];
let calls = -1;
const useState = (def) => {
const callId = ++calls;
if (states[callId]) {
return states[callId];
}
const setDef = (newV) => {
states[callId][0] = newV;
reRender();
};
const state = [def, setDef];
states.push(state);
return state;
};
function MadeUseStateMyself() {
const [minutes, setMinutes] = useState(5);
const [error, setError] = useState(null);
const handleAdd = () => {
if (minutes < 9) {
setMinutes(minutes + 1);
setError(null);
} else {
setError("Less than 10 please");
}
};
const handleSubStract = () => {
if (minutes > 0) {
setMinutes(minutes - 1);
setError(null);
} else {
setError("More than 0 please");
}
};
return (
<React.Fragment>
<button onClick={handleSubStract}> - </button>
<p>{minutes}</p>
<button onClick={handleAdd}> + </button>
{error && <div>{error}</div>}
</React.Fragment>
);
}
function reRender() {
calls = -1;
ReactDOM.render(
<React.StrictMode> // <-- add the React.StrictMode
<MadeUseStateMyself />
</React.StrictMode>,
document.getElementById("root")
);
}
reRender(); // <-- Invoke immediately
Upvotes: 1