0

I'm building a React.js application where I need to conditionally render components based on user interactions (like tabs or dynamic forms). The issue is that when a component is unmounted and later remounted, its local state is lost.

function App() {
  const [view, setView] = useState('A');

  return (
    <>
      <button onClick={() => setView('A')}>Show A</button>
      <button onClick={() => setView('B')}>Show B</button>

      {view === 'A' && <ComponentA />}
      {view === 'B' && <ComponentB />}
    </>
  );
}

function ComponentA() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Count A: {count}</button>;
}
2
  • 2
    Yes that's how state works. There's currently no option to preserve it after unmounting. You'd need to pass it from a parent that doesn't get unmounted or use a global state Commented Jul 20 at 10:37
  • 2
    Or don't unmount them but hide instead. Both options are acceptable for tabs, etc Commented Jul 20 at 10:40

3 Answers 3

0

Accordingly to suggestions you could just hide component by manipulating display CSS property. This way you will keep hidden component alive and not loose its state"

function App() {
    const [view, setView] = useState('A')

    return (
        <>
            <button onClick={() => setView('A')}>Show A</button>
            <button onClick={() => setView('B')}>Show B</button>

            <ComponentA display={view === 'A' ? 'block' : 'none'} />
            <ComponentB display={view === 'B' ? 'block' : 'none'} />
        </>
    )
}

function ComponentA({ display }: { display: string }) {
    const [count, setCount] = useState(0)
    return (
        <button style={{ display }} onClick={() => setCount(count + 1)}>
            Count A: {count}
        </button>
    )
}
Sign up to request clarification or add additional context in comments.

Comments

0

If the state of your components must survive their existence, then it means they are not the state of your components...but they are the state of your application.

Hence, in order to achieve what you need, you just have to move the state that you want to be preserved up to the application itself - the root component.

Comments

0

Store your state in outer scope.

It could done by

  • store in outer component (this method is complicate )
  • or global scope.

For store state in global scope. You can use state management library eg. Redux, Rxjs, ... or with common variable could done this.

Example for use Rxjs for state management.

//state.js
const store = new rxjs.BehaviorSubject(0);//state is store here

function useCounter(){ //this is just function for connect store to react
  const [value, setValue] = React.useState(store.getValue());
  
  React.useEffect(()=>{
    
    const sub = store
      .pipe(rxjs.skip(1), rxjs.distinctUntilChanged())
      .subscribe((v) => { setValue(v) })
    return ()=>{
        sub.unsubscribe();
    }
  }, [])
  
  return [value, (n) => { store.next(n)}]
}

//ComponentB.js
function ComponentB() {
  const [count, setCount] = useCounter();
  console.log("render b", count);
  return <button onClick={() => setCount(count + 1)}>Count B: {count}</button>;
}

//ComponentA.js
function ComponentA() {
  const [count, setCount] = useCounter();
  console.log("render a", count);
  return <button onClick={() => setCount(count + 1)}>Count A: {count}</button>;
}

//app.js
function App() {
  const [view, setView] = React.useState('A');

  return (
    <>
      <button onClick={() => setView('A')}>Show A</button>
      <button onClick={() => setView('B')}>Show B</button>
      <br/>
      <br/>
      {view === 'A' && <ComponentA />}
      {view === 'B' && <ComponentB />}
    </>
  );
}


const root = ReactDOM.createRoot(document.getElementById('app-host'));
root.render(<App />);
<script src="https://unpkg.com/rxjs@^7/dist/bundles/rxjs.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>


<app-host id="app-host">
</app-host>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.