GithubHelp home page GithubHelp logo

Comments (9)

kassens avatar kassens commented on June 21, 2025 1

A reduced repro of this change is

import { useState } from "react";

let stateId = 0;
export default function App() {
  stateId++;
  const [state] = useState(stateId);
  return state;
}

What is happening here is that in React the App component is rendered twice. In 19 React preserves the state from the first render.

I think this is intentional by React preserving and re-using more state, but someone else might correct me.

from react.

MohamedYassineBenomar avatar MohamedYassineBenomar commented on June 21, 2025

This issue seems interesting! I would love to contribute or discuss further. ๐Ÿ‘

from react.

ry-krystal avatar ry-krystal commented on June 21, 2025

This behavior is likely due to how React handles state and component updates in the given version. It seems like React is treating the useState call as if it is creating a new state object each time the component re-renders, which should not happen in a normal scenario. The behavior can be linked to potential issues or changes in state handling, particularly in versions around [email protected] as mentioned in the screenshotใ€‚

Solution and Recommendation:
Ensure Stable useState Behavior: Make sure that useState is only called once for the same component instance, without causing unnecessary state recreation. This can be achieved by ensuring that the initialization logic is stable and not tied to re-renders.

Verify React Version and Known Issues:

Check the React version you are using and look for related issues in the React repository. The issue link (#29634) mentioned in the screenshot might provide more context.
Consider upgrading or downgrading React to see if this behavior changes, as it could be a bug or regression in a particular version.
Alternative State Management: If this behavior is confirmed as a bug or unintended side effect, consider using a different state management approach, such as useRef or useReducer, to maintain stable references and avoid unexpected destruction of state objects.

Modified Code Example (If Needed):
To illustrate a more stable approach using useRef instead of useState for maintaining object references:

import { useEffect, useRef } from "react";

let stateId = 0;
export default function App() {
const stateRef = useRef({
stateId: console.log(++stateId, "created") || stateId,
destroy() {
console.log(state ${this.stateId} destroyed);
},
});

useEffect(() => {
return () => {
stateRef.current.destroy();
};
}, []);

console.log("render state", stateRef.current);
return

state: {stateRef.current.stateId}
;
}
Key Changes:
Replaced useState with useRef to maintain a stable reference to the state object.
This ensures that the destroy method is only called when the component is unmounted, avoiding unexpected destruction of the state object.
By understanding the root cause and applying the appropriate fix, the component can behave predictably across different React versions.

from react.

akashvivek avatar akashvivek commented on June 21, 2025

Is this issue still opened ?

from react.

dislido avatar dislido commented on June 21, 2025

Is this issue still opened ?

Yes, neither React 19.x nor 18.x has solved this issue

from react.

MeerArsalanAli27 avatar MeerArsalanAli27 commented on June 21, 2025

It seems there's an issue with how the useEffect cleanup function references the state in StrictMode. The current implementation logs the initial stateId during cleanup, which can lead to confusion since stateId increments with each render.

To fix this, consider using an updateState function that retains the destroy method while creating a new state with an incremented stateId. This ensures the cleanup function references the correct state:` import { useEffect, useState } from "react";

let stateId = 0;

export default function App() {
const [state, setState] = useState({
stateId: ++stateId,
destroy() {
console.log(state ${this.stateId} destroyed);
},
});

useEffect(() => {
return () => {
state.destroy();
};
}, [state]);

const updateState = () => {
setState({
stateId: ++stateId,
destroy: state.destroy, // Retain the destroy function from the previous state
});
};

console.log("render state", state);

return (


state: {state.stateId}

Update State

);
}
`

from react.

dislido avatar dislido commented on June 21, 2025

A more practical example

//In this example, it is a websocket connection, which can also be any object that is not suitable for creating in each rendering and should be destroyed when not use
class Connection {
  constructor() {
    // create ws connection
  }
  destroy() {
    // close ws connection
  }
}

function initState() {
  return new Connection();
}
export default function App() {
  const [connection, setConnection] = useState(initState);
  useEffect(() => {
    return () => {
      connection.destroy();
    };
  }, [state]);

  const reconnect = () => setConnection(initState())
  return null;
}

Of course, we can easily solve this problem through the following way:

// init connection in useEffect
export default function App() {
  const [connection, setConnection] = useState();
  useEffect(() => {
    const newConnection = initState();
    setConnection(newConnection)
    return () => {
      newConnection.destroy();
    };
  }, [state]);
  // But the type of connection become `Connection | undefined`, 
  // This will add some additional check logic
  useMemo(() => {
    if (!connection) return null; // <-
    return connection;
  }, []);

  return null;
}

from react.

github-actions avatar github-actions commented on June 21, 2025

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!

from react.

github-actions avatar github-actions commented on June 21, 2025

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!

from react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.