Home > database >  How to render the next component in React?
How to render the next component in React?

Time:12-01

I have three components First, Second and Third that need to render one after the other.

My App looks like this at the moment:

function App() {
  return (
    <First/>
  )
}

So ideally, there's a form inside First that on submission (onSubmit probably) triggers rendering the Second component, essentially getting replaced in the DOM. The Second after some logic triggers rendering the Third component and also passes a value down to it. I'm not sure how to go on about it.

I tried using the useState hook to set a boolean state to render one of the first two components but I would need to render First, then somehow from within it change the set state in the parent which then checks the boolean and renders the second. Not sure how to do that. Something like below?

function App() {
  const { isReady, setIsReady } = useState(false);
  return (
    isReady
    ? <First/> //inside this I need the state to change on form submit and propagate back up to the parent which checks the state value and renders the second? 
    : <Second/>
  );
}

I'm mostly sure this isn't the right way to do it. Also need to figure out how to pass the value onto another component at the time of rendering it and getting replaced in the DOM. So how does one render multiple components one after the other on interaction inside each? A button click for example?

Would greatly appreciate some guidance for this.

CodePudding user response:

then somehow from within it change the set state in the parent which then checks the boolean and renders the second.

You're actually on the right track.

In React, when you're talking about UI changes, you have to manage some state.
So we got that part out of the way.

Now, what we can do in this case is manage said state in the parent component and pass functions to the children components as props in-order to allow them to control the relevant UI changes.

Example:

function App() {
  const { state, setState } = useState({
    isFirstVisible: true,
    isSecondVisible: false,
    isThirdVisible: false,
  });

  const onToggleSecondComponent = (status) => {
    setState(prevState => ({
      ...prevState,
      isSecondVisible: status
    }))
  }

  const onToggleThirdComponent = (status) => {
    setState(prevState => ({
      ...prevState,
      isThirdVisible: status
    }))
  }

  return (
    {state.isFirstVisible && <First onToggleSecondComponent={onToggleSecondComponent} /> }
    {state.isSecondVisible && <Second onToggleThirdComponent={onToggleThirdComponent} /> }
    {state.isThirdVisible && <Third/> }
  );
}

Then you can use the props in the child components. Example usage:

function First({ onToggleSecondComponent }) {

  return (
    <form onSubmit={onToggleSecondComponent}
      ...
    </form
  )
}

Note that there are other ways to pass these arguments.
For example, you can have one function in the parent comp that handles them all, or you can just pass setState to the children and have them do the logic.
Either way, that's a solid way of achieving your desired outcome.

CodePudding user response:

Seen as your saying there are stages, rather than having a state for each stage, just have a state for the current stage, you can then just increment the stage state to move onto the next form.

Below is a simple example, I've also used a useRef to handle parent / child state, basically just pass the state to the children and the children can update the state. On the final submit I'm just JSON.stringify the state for debug..

const FormContext = React.createContext();
const useForm = () => React.useContext(FormContext);

function FormStage1({state}) {
  const [name, setName] = React.useState('');
  state.name = name;
  return <div>
    Stage1:<br/>
    name: <input value={name} onChange={e => setName(e.target.value)}/>
  </div>
}

function FormStage2({state}) {
  const [address, setAddress] = React.useState('');
  state.address = address;
  return <div>
    Stage2:<br/>
    address: <input value={address} onChange={e => setAddress(e.target.value)}/>
  </div>
}

function FormStage3({state}) {
  const [hobbies, setHobbies] = React.useState('');
  state.hobbies = hobbies;
  return <div>
    Stage3:<br/>
    hobbies: <input value={hobbies} onChange={e => setHobbies(e.target.value)}/>
  </div>
}


function Form() {
  const [stage, setStage] = React.useState(1);
  const state = React.useRef({}).current;
  let Stage;
  if (stage === 1) Stage = FormStage1
  else if (stage === 2) Stage = FormStage2
  else if (stage === 3) Stage = FormStage3
  else Stage = null;
  
  return <form onSubmit={e => {
    e.preventDefault();
    setStage(s => s   1);
  }}>
    {Stage 
      ? <React.Fragment>
        <Stage state={state}/>
        <div>
          <button>Submit</button>
        </div>
      </React.Fragment>
      : <div>
        {JSON.stringify(state)}
      </div>     
    }    
  </form>
  
}



const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Form/>);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<div id="root"></div>

  • Related