question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add `get` function to `useState`

See original GitHub issue

Do you want to request a feature or report a bug?

  • feature

What is the current behavior? Code from Introducing Hooks:

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
// each time "count" changed, this arrow function will be created again.
// so that it can access the latest "count"
onClick={() => setCount(count + 1)}

I don’t think it is good to create a fixed function many times, so I try to modify the code: (Update on Jul 2022: No matter using the inline anonymous function or wrapping with useCallback, the function will always be created. The difference is that, in useCallback approach, the function reference will not be changed, which could be helpful if we use memo to wrap the component who receives the function as a property)

const [count, setCount] = useState(0);
const handleClick = useCallback(() => setCount(count + 1), []);

But obviously the callback in useCallback couldn’t get the latest count because I pass in an empty inputs array to avoid this callback been generated again and again.

So, in fact, the inputs array decide two things:

  1. when to recreate the callback
  2. which state can be accessed in the callback

In most situation, the two things are one thing, but here they conflict.

So I think maybe it’s good to add a get function to useState like this:

import { useState, useCallback } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount, getCount] = useState(0);

  const handleClick = useCallback(() => setCount(getCount() + 1), []);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={handleClick}>
        Click me
      </button>
    </div>
  );
}

Maybe it’s confusing because getCount can totally replace count, but it brings the possible to avoid creating callbacks again and again.

Edited

https://github.com/facebook/react/issues/14543#issuecomment-452237355 exactly resolves the case above. But there‘re many other scenarios can’t use updater to resolve. Here are some more code snippets:

1. Access states in a timer.

useEffect(() => {
  // or setInterval
  const id = setTimeout(() => {
    // access states
  }, period);
  return () => clearTimeout(id);
}, inputs);

2. Access states in WebSocket callbacks

useEffect(() => {
  // create a WebSocket client named "ws"
  ws.onopen = () => {
    // access states
  };
  ws.onmessage = () => {
    // access states
  };
  return () => ws.close();
}, inputs);

3. Access states in Promise

useEffect(() => {
  create_a_promise().then(() => {
    // access states
  });
}, inputs);

4. Access states in event callbacks

useEffect(() => {
  function handleThatEvent() {
    // access states
  }
  instance.addEventListener('eventName', handleThatEvent);
  return instance.removeEventListener('eventName', handleThatEvent);
}, inputs);

We had to use some workaround patterns to resolve those cases, like https://github.com/facebook/react/issues/14543#issuecomment-452676760 https://github.com/facebook/react/issues/14543#issuecomment-453058025 https://github.com/facebook/react/issues/14543#issuecomment-453079958 Or a funny way:

const [state, setState] = useState();
useEffect(() => {
  // or setInterval
  const id = setTimeout(() => {
    // access states
    setState((prevState) => {
      // Now I can do anything with state...🤮
      ...
      return prevState;
    });
  }, period);
  return () => clearTimeout(id);
}, inputs);

So let’s discuss and wait… https://github.com/facebook/react/issues/14543#issuecomment-452713416

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn’t have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:

What is the expected behavior?

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

  • React 16.7.0-alpha.2

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:10
  • Comments:33 (2 by maintainers)

github_iconTop GitHub Comments

16reactions
saranchonkaucommented, Jan 8, 2019

@liyuanqiu you can use updater function in setCount

const handleClick = useCallback(() => setCount(prevCount => prevCount + 1), []);

useState API reference

9reactions
ignatiusrezacommented, Jan 9, 2019

I really like the suggestion for having pair of getter and setter returned from useState… which would make it easier to keep things fresh… if it doesn’t end up in the official implementation, I think it can be implemented in user land using custom hook like:

const useGetterState = (initialState) => {
  const [state, setState] = useState(initialState);
  const stateRef = useRef(state);
  useEffect(() => {
    stateRef.current = state
  }, [state]);

  return [() => stateRef.current, setState];
}

?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using the State Hook - React
A Hook is a special function that lets you “hook into” React features. For example, useState is a Hook that lets you add...
Read more >
useState in React: A complete guide - LogRocket Blog
useState is a Hook that allows you to have state variables in functional components. You pass the initial state to this function and...
Read more >
is it possible to React.useState(() => {}) in React?
It is possible to set a function in state using hooks, but because state can be initialized and updated with a function that...
Read more >
How to store a function with the useState hook in React
When you do this, the argument of the function you pass contains the current value. For example, a mutation that doubles the current...
Read more >
how tf do you store a function with the useState hook?
passing an argument-less function to useState that returns the initial value. ... the function as the initial value. ... to handle functions and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found