38

I've been learning/experimenting with React hooks. When I go to inspect the values of the current state of a component using React DevTools in Chrome, I see the state fine, but the actual 'fields' -- that is, the state variables that are being updated by the individual useState hooks -- don't have any name associated with them. Instead, I see, for example, several strings, a couple of booleans, etc. I can generally figure out what's going on, but this seems problematic -- I'd like to be able to see which what the state variable's name is.

For instance, if I have something like

const [doughnuts, setDoughnuts] = useState(24)

When I look in React DevTools I'd like to see something like `doughnuts: number : 24', instead of just 'number: 24'.

Am I missing some setting somewhere, or some technique to turn on this ability?

chumakoff
  • 6,807
  • 2
  • 23
  • 45
Cerulean
  • 5,543
  • 9
  • 59
  • 111

5 Answers5

55

Finally react team listened to us

The recent introduction of parsing custom hooks in react dev tools option might help
.

Before parsing ( before clicking the magic button in custom hooks card )

enter image description here

. enter image description here .

After parsing ( clicking the magic button in the top right )

enter image description here

Siva Kannan
  • 2,237
  • 4
  • 27
  • 39
29

Some approaches not mentioned in the other answers:

  1. Use the following:(suggested by Oleh)
const [{ item }, setItem] = useState({ item: 2 });

You could also wrap the useState function so that, based on the shape of the initial value, the setItem function it returns auto-converts from the passed value itself into an object with the correct (wrapper) shape.

  1. Create a new useStateWithLabel function:
function useStateWithLabel(initialValue, name) {
    const [value, setValue] = useState(initialValue);
    useDebugValue(`${name}: ${JSON.stringify(value)}`);
    return [value, setValue];
}

It's based on the useDebugValue function described here.

Usage:

const [item, setItem] = useStateWithLabel(2, "item");
Venryx
  • 15,624
  • 10
  • 70
  • 96
  • 1
    For object, use this: `useDebugValue(name + ":" + JSON.stringify(value));` – Ayan May 24 '21 at 12:08
  • @Ayan Good point; edited the answer to use `JSON.stringify`, since that works for both primitives and objects. – Venryx Mar 26 '22 at 10:10
5

When you do the following operation

const [item, setItem] = useSate(2)

You're using destructuring assignment in an array a type which does not contain a key like an object. You're just creating an alias to access the first element of the array returned by useState. If you do something like this

const [item, setItem] = useState({value: 2})

You will be able to see value: 2 in your dev-tools, cause it reflects the current state of that hook at a certain point of time.

Each time you call a Hook, it gets isolated local state within the currently executing component based on the previous value, so the identifier attributed by you (item) will only be scoped to that render cycle, but it doesn't mean that React reference is using the same identifier.

Dupocas
  • 20,285
  • 6
  • 38
  • 56
  • 2
    what if we do `const [{ item }, setItem] = useState({ item: 2 });` to avoid having additional names and dev tools will have something to show us – Oleh Oct 16 '19 at 08:28
  • @Oleh It seems like that would work, neat idea. You could also wrap the `useState` function so that, based on the shape of the initial value, the `setItem` function it returns auto-converts from the value itself into an object with the correct (wrapper) shape. – Venryx Oct 27 '19 at 13:39
5

You are not missing anything and you can't change this behaviour. This is how React deals with multiple state.

https://reactjs.org/docs/hooks-rules.html#explanation.

One way to avoid this problem is to use a single State Hook which creates a single state including all the data.

const [state, setState] = useState({doughnuts: 24, key1: 'value1', key2: 'value2'});

In this case the state is stored in a single object and each value is associated with a key.

Take a look at this: Should I use one or many state variables?

A compound state is hard to manage, but there is a tool which can help you with that: useReducer Hook

Ray
  • 2,713
  • 3
  • 29
  • 61
chumakoff
  • 6,807
  • 2
  • 23
  • 45
  • 2
    Don't advice to use `useState()` for complex object state, instead use `useReducer()` would save your time from unnecessary headaches. – Alexander Kim Apr 04 '20 at 04:53
  • IMHO forcing the use of a single State Hook just to render easier the debugging of a react component doesn't seem a solid reason. Be aware that React team suggests: _However, **we recommend to split state into multiple state variables based on which values tend to change together**_. (...) _It makes it easy to later extract some related logic into a custom Hook_. (Cited from the same source @chumakoff suggested: Should I use one or many state variables?) – Delmo Jan 03 '22 at 23:23
4

You can use useDebugState hook from use-named-state package.

import { useDebugState } from "use-named-state";
const App = () => {
  const [counter, setCounter] = useDebugState("counter", 0);

  return <button onClick={(prevCount) => prevCount + 1}>{counter}</button>;
};

It internally uses useDebugValue hook from react (method suggested by @Venryx)

Bhumij Gupta
  • 369
  • 3
  • 6