Next.js Discord

Discord Forum

Conditional rendering

Answered
WhyFencePost posted this in #help-forum
Open in Discord
I have a value of state, which updates properly, but i need a way to conditionally render different components based on state. State can change at any time. Every way I have tried fails.
What I have tried:
1.
if (state == 0) {
  return (
    //Components here
  );
}

2.
return (
  {state == 0 && //Component here}
);

3.
return (
  {state == 0 ? //Component here , //Other component here}
);


Not one of those changes what is displayed when state changes, so what is the right way to do this? BTW state is a state, using useState()
Answered by WhyFencePost
I did some digging, and the issue seems to be related to something called shallow equality, which has to do with when an object re-renders (the state needs to be changed on the object itself it seems). I need to change it from the child, so i need a different way to force a re-render of this object when a child's state changes. To do this I needed to change the let state to a useState instead of a variable, making the component re-render on state change. Therefore my final code looks like this:
function Login() {
  const [pwString, setPwString] = useState("");
  const [userString, setUserString] = useState("");
  const [componentState, setComponentState] = useState(1); //NOTICE THE CHANGE HERE

  useEffect(() => {
    if (pwString != "") {
      setComponentState(0);
      //Login Logic
      //Wait in debug and switch to 3
      setComponentState(3); //debug
    } else if (userString != "") {
      setComponentState(0);
      //Login Logic
      //Wait in debug and switch to 2
      setComponentState(2); //debug
    }
  }, [userString, pwString]);

  return (
    <>
      <div className="w-screen h-screen">
        {componentState == 1 ? <LoginPage1 setUserString={setUserString} userString={userString} /> : <h1>This is not one</h1>}
      </div>
    </>
  );
}
View full answer

3 Replies

Great golden digger wasp
Bro you third approach should work, the reason that it is not working because you make a syntax mistake in their.
I have created a example react app for you so you can better understand
import { useState } from "react";

function App() {
  const [state, setState] = useState(0);

  return (
    <>
      <button
        onClick={() => {
          setState(state + 1);
        }}>
        Plus
      </button>
      <button
        onClick={() => {
          setState(state - 1);
        }}>
        Minus
      </button>
      <h1>{state}</h1>
      {state == 1 ? <h1>1</h1> : <h1>This is not one</h1>}
    </>
  );
}

export default App;

If you have any question you can ask.
@Great golden digger wasp Bro you third approach should work, the reason that it is not working because you make a syntax mistake in their. I have created a example react app for you so you can better understand javascript import { useState } from "react"; function App() { const [state, setState] = useState(0); return ( <> <button onClick={() => { setState(state + 1); }}> Plus </button> <button onClick={() => { setState(state - 1); }}> Minus </button> <h1>{state}</h1> {state == 1 ? <h1>1</h1> : <h1>This is not one</h1>} </> ); } export default App; If you have any question you can ask.
does not work, logging the state it updates, but the stuff that is shown does not:
function Login() {
  const [pwString, setPwString] = useState("");
  const [userString, setUserString] = useState("");
  let state = 1;

  useEffect(() => {
    if (pwString != "") {
      state = 0;
      //Login Logic
      //Wait in debug and switch to 3
      state = 3; //debug
    } else if (userString != "") {
      state = 0;
      //Login Logic
      //Wait in debug and switch to 2
      state = 2; //debug
    }
  }, [userString, pwString]);

  return (
    <>
      <div className="w-screen h-screen">
        {state == 1 ? <LoginPage1 setUserString={setUserString} userString={userString} /> : <h1>This is not one</h1>}
      </div>
    </>
  );
}

The setState is in a child of this (the LoginPage1)
I did some digging, and the issue seems to be related to something called shallow equality, which has to do with when an object re-renders (the state needs to be changed on the object itself it seems). I need to change it from the child, so i need a different way to force a re-render of this object when a child's state changes. To do this I needed to change the let state to a useState instead of a variable, making the component re-render on state change. Therefore my final code looks like this:
function Login() {
  const [pwString, setPwString] = useState("");
  const [userString, setUserString] = useState("");
  const [componentState, setComponentState] = useState(1); //NOTICE THE CHANGE HERE

  useEffect(() => {
    if (pwString != "") {
      setComponentState(0);
      //Login Logic
      //Wait in debug and switch to 3
      setComponentState(3); //debug
    } else if (userString != "") {
      setComponentState(0);
      //Login Logic
      //Wait in debug and switch to 2
      setComponentState(2); //debug
    }
  }, [userString, pwString]);

  return (
    <>
      <div className="w-screen h-screen">
        {componentState == 1 ? <LoginPage1 setUserString={setUserString} userString={userString} /> : <h1>This is not one</h1>}
      </div>
    </>
  );
}
Answer