DEV Community

Emmanuel Villalobos
Emmanuel Villalobos

Posted on

Challenge: Write a useState hook without copying React's

Hi there,
Yesterday I came up with the idea of building my own useState function. I thought it'd be easy, since we can always use lexical's scope. So I tried it. And it didn't work.

If you see, I created a higher-order function to persist the value of the variable current, in the returned function, I return the actual values we would need.

The problem is, after I call the setCounter function several times, it does persist the current state and successfully update it, but doesn't return it.

I tried returning [current, updateValue] directly from useState function, but in that case, updateValue doesn't keep its lexical scope. So my last code is what I think is the closest.

What I can think by looking at this error, I'm not passing a reference but the actual value. I remember the way to work with references is with objects and arrays, I tried the objects' approach but I'm not sure if it was badly implemented and the array reference I don't even know how that works. I would expect that returning [current, updateValue] from updateValue function would do the magic, but it doesn't.

As I said, I'm trying to solve this not looking at React's code for useState. I want to create it myself, maybe with some help.

What do you guys think I'm missing? Have you tried doing a useState of your own?

Best regards!

Oldest comments (4)

Collapse
 
benlesh profile image
Ben Lesh

useState in React is counting on the order in which it's called, inside a given component instance, to access values stored in global state. Since React is in control of it's own render cycle when React's useState is called, it has one piece of the lookup: The component instance. The other part comes from when useState is called (this is why you can't put it in a conditional). So. If you wanted to build this yourself, your useState would at least need to take in some unique identifier in place of the component instance. I hope that helps.

Collapse
 
emmanuer profile image
Emmanuel Villalobos

Well, you're right. That's an extra layer I should be thinking of- I'll see what I can do. Thanks for your help!

Collapse
 
muhammedberakoc profile image
Bera

Using closures is a good idea. I am not sure how they done the first part of [value, setValue] since when I tried it, it always gives the initial value.
Mine is like that: repl.it/repls/VioletredUniformTree...

Collapse
 
kiranmantha profile image
Kiran Mantha • Edited

try as below:

const isFunction = value => typeof value === 'function';

function useState(obj) {
  let initialState = obj;
  const reducer = fn => {
    let newState;
    if (isFunction(fn)) {
      newState = fn(initialState);
    } else {
      newState = fn;
    }
    Object.assign(initialState, newState);
  };
  return [initialState, reducer];
}

// Usage
const [state, handler] = useState({ a: 1, b: 2 })
console.log('initial state', state);
handler((prevState) => ({ ...prevState, b: 3 }))
console.log('modified state', state);
handler({b: 5});
console.log('modified state', state);
Enter fullscreen mode Exit fullscreen mode