Skip to content

Instantly share code, notes, and snippets.

@ryardley
Created October 31, 2018 01:59
Show Gist options
  • Select an option

  • Save ryardley/e83bad1985740ab33b18fc578ec1957a to your computer and use it in GitHub Desktop.

Select an option

Save ryardley/e83bad1985740ab33b18fc578ec1957a to your computer and use it in GitHub Desktop.
let state = [];
let setters = [];
let firstRun = true;
let cursor = 0;
function createSetter(cursor) {
return function setterWithCursor(newVal) {
state[cursor] = newVal;
};
}
// This is the pseudocode for the useState helper
export function useState(initVal) {
if (firstRun) {
state.push(initVal);
setters.push(createSetter(cursor));
firstRun = false;
}
const setter = setters[cursor];
const value = state[cursor];
cursor++;
return [value, setter];
}
// Our component code that uses hooks
function RenderFunctionComponent() {
const [firstName, setFirstName] = useState("Rudi"); // cursor: 0
const [lastName, setLastName] = useState("Yardley"); // cursor: 1
return (
<div>
<Button onClick={() => setFirstName("Richard")}>Richard</Button>
<Button onClick={() => setFirstName("Fred")}>Fred</Button>
</div>
);
}
// This is sort of simulating Reacts rendering cycle
function MyComponent() {
cursor = 0; // resetting the cursor
return <RenderFunctionComponent />; // render
}
console.log(state); // Pre-render: []
MyComponent();
console.log(state); // First-render: ['Rudi', 'Yardley']
MyComponent();
console.log(state); // Subsequent-render: ['Rudi', 'Yardley']
// click the 'Fred' button
console.log(state); // After-click: ['Fred', 'Yardley']
@nghiahung-dev
Copy link

I think the variable firstRun's position is not right. The variable is not global variable, it should is a part of useState function.

prev...
useState(initVal) {
const firstRun = !state[cursor]
  if (firstRun) {
    state.push(initVal);
    setters.push(createSetter(cursor));
  }
after...

WDYT?

@Jeneko
Copy link

Jeneko commented Jan 7, 2024

I see the problem with the firstRun variable too.
The call of useState("Rudi") sets firstRun to false, so next call of useState("Yardley") won't push it's initialVal to the state:

if (firstRun) {
    state.push(initVal); // won't happen
...

I think it can be addressed by replacing the check of firstRun with the following check:

if (state.length <= cursor) {
    state.push(initVal);
...

@vv1vv2
Copy link

vv1vv2 commented Dec 12, 2025

if (firstRun) { state.push(initVal); setters.push(createSetter(cursor)); firstRun = false; } does it mean only the first useState can run correctly due to the subsequent useState calling will not enter the if block

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment