react icon indicating copy to clipboard operation
react copied to clipboard

Bug: Repeated state setter callbacks when callback throws

Open farsightsoftware opened this issue 2 years ago • 8 comments
trafficstars

It's a minor thing, but confusing: If you call a useState state setter and the callback throws, React calls the state setter callback twice more before allowing the error to propagate to the console (then twice more after that, with a development build). This obscures the nature of the error. I'd expect the callback to be called just once. This happens both with dev and prod builds of the library (though the number of calls varies), and without StrictMode.

React version: 18.2.0

Steps To Reproduce

  1. Call a state setter passing in a callback that throws

Link to code example: https://codesandbox.io/s/react-state-setter-oddity-40jgq5?file=/src/index.js (but look in the actual console, not the CodeSandbox console, it doesn't show everything).

function App() {
    const [value, setValue] = useState(0);

    const update = () => {
        console.log("calling state setter");
        setValue((v) => {
            console.log("state setter callback called");
            if (Math.random() < 1) {
                //           ^^^^ Always true, just to fool ESLint
                throw new Error("!!"); // <== Stand-in for code that throws unexpectedly
            }
            console.log("state setter callback returned");
            return v + 1;
        });
    };

    return (
        <div className="app">
            <div>Value: {value}</div>
            <input type="button" onClick={update} value="Update" />
        </div>
    );
}

The current behavior

In development, calling update causes the state setter callback to be called a total of five times: Three prior to the error being reported in the console, then twice more, with the error appearing a total of three times.

calling state setter
state setter callback called
state setter callback called
state setter callback called
Uncaught Error: !!
    at ...
state setter callback called
state setter callback called
Uncaught Error: !!
    at ...
The above error occurred in...
Uncaught Error: !!
    at ...

WIth a production build, the state setter callback is called three times, and the error reported twice (https://thenewtoys.dev/temp/react-repeating-state-setter):

calling state setter
state setter callback called
state setter callback called
state setter callback called
Error: !!
    at ...
Uncaught Error: !!
    at ...

The expected behavior

Calling update should cause the state setter callback to be called just once, and the error to be reported just once.

calling state setter
state setter called
Uncaught Error: !!
    at ...
The above error occurred in...

As I say, it's a minor thing, but the current behavior obscures the nature of the error. In my case, the error I was getting seemed to be a result of the repeated (seemingly-recursive) calls to the callback, so I was looking for a way my code could be doing that (since select isn't broken :-) ). But eventually I realized it was React doing the repeated calls.

farsightsoftware avatar Apr 28 '23 10:04 farsightsoftware

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

github-actions[bot] avatar Apr 09 '24 16:04 github-actions[bot]

Yes, this affects us. It took hours to figure out the first time, and despite best efforts, if we have a but causing a setter to throw again there's every chance we'll fail to remember this and spend hours debugging it again (sad but true :-) ).

tjcrowder avatar Apr 09 '24 16:04 tjcrowder

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

github-actions[bot] avatar Jul 09 '24 22:07 github-actions[bot]

bot - bump

tjcrowder avatar Jul 16 '24 15:07 tjcrowder

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

github-actions[bot] avatar Oct 14 '24 18:10 github-actions[bot]

bot - bump

tjcrowder avatar Oct 15 '24 06:10 tjcrowder

This is intended. We render again on error to hope we may recover from the error. That's why state setters must be pure so that we can call them at any point.

eps1lon avatar Oct 15 '24 09:10 eps1lon

This is intended. We render again on error to hope we may recover from the error.

That's an extremely odd and surprising thing to do. I can't think of a single other library I've ever used that would silently repeat a callback that had thrown in hopes it worked the next time. Where is this documented and the rationale explained?

tjcrowder avatar Oct 15 '24 09:10 tjcrowder

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

github-actions[bot] avatar Jan 13 '25 10:01 github-actions[bot]

Not stale.

@eps1lon - I should have tagged you in my comment and question above. Thanks.

tjcrowder avatar Jan 13 '25 12:01 tjcrowder

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

github-actions[bot] avatar Jun 10 '25 18:06 github-actions[bot]

sigh Not stale.

tjcrowder avatar Jun 10 '25 19:06 tjcrowder

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

github-actions[bot] avatar Sep 08 '25 21:09 github-actions[bot]

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!

github-actions[bot] avatar Sep 15 '25 21:09 github-actions[bot]