Home > Back-end >  Using multiple buttons to navigate on the same webpage on React
Using multiple buttons to navigate on the same webpage on React

Time:01-08

I am just messing around in React as a beginner. I am trying to make a questionnaire. I ask the user whether they have a laptop, and then continue asking questions about it. If the 'yes' button is clicked on the first question, the next question is displayed - what kind of laptop. Here I want to display 3 options in the form of buttons instead of 2 like the previous question and the chain continues. If 'no' is clicked on the first question, another question is displayed. I want these questions to be on the same webpage and not redirected to another page. I also want the upcoming question buttons to not be displayed initially itself. I have a good understanding of HTML and JS and basic level fundamentals of React.

class App extends React.Component {

  constructor() {
    super(); 
    this.state = { showMessage: false }
  }

  _showMessage = (bool) => {
    this.setState({
      showMessage: bool
    });
  }

  render() {
    return (
      <div>
        Do you have a laptop <br/>
        <button onClick={this._showMessage.bind(null, true)}>yes</button>
        <button onClick={this._showMessage.bind(null, false)}>no</button>
        { this.state.showMessage && (<div>What kind of laptop?</div>) }
        <br/>
{/* I want to hide these buttons until the 'yes' button is clicked*/}
        <button onClick={this._showMessage.bind(null, true)}>Windows</button>
        <button onClick={this._showMessage.bind(null, false)}>IOS</button>
{/* I want to display a third button which says none of the above */}
        { this.state.showMessage && (<div>when did you buy it?</div>) }
    </div> )
  }
}

CodePudding user response:

You can store the current step in the state, increase it each time you click on the desired button and, depending on the step, display the necessary content on the page.

const App = () => {
      const [step, setStep] = React.useState(1)

      const handleNextStep = () => setStep(prevStep => prevStep   1)

      const handleFirstStep = () => setStep(1)

      return (
        <div>
          Do you have a laptop <br/>
          <button onClick={handleNextStep}>yes</button>
          <button onClick={handleFirstStep}>no</button>
          {step > 1 && (
            <>
              <div>What kind of laptop?</div>
              <br/>
              <button onClick={handleNextStep}>Windows</button>
              <button onClick={handleNextStep}>IOS</button>
            </>
          )}

          {step > 2 && (<div>when did you buy it?</div>)}
        </div>
      )
    }

const root = ReactDOM.createRoot(document.querySelector("#root"))
root.render(<App />)
<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>
<body>
  <div id="#root"/>
</body>

CodePudding user response:

Not 100% sure about your question, but it seems you have several steps, so you could switch activeStep and render nessesary content based on activeStep

class App extends React.Component {

  constructor() {
    super(); 
    this.state = { activeStep: 1 }
  }

  moveToNextStep = (step) => {
    this.setState({
      activeStep: step
    });
  }

  render() {
    return (
     {/* STEP 1 */}
     {this.state.activeStep === 1 && (
        <div>
          Do you have a laptop <br/>
          {/* move to step 2 */}
          <button onClick={() => this.moveToNextStep(2)}>yes</button>
          {/* move to some other step... */}
          <button onClick={() => {}}>no</button>
        </div>
      )}
      {/* STEP 2 */}
      {this.state.activeStep === 2 && (
         <div>
           What kind of laptop?<br/>
           {/* move to step 3 */}
           <button onClick={() => this.moveToNextStep(3)}>Windows</button>
           {/* move to some other step and etc.... */}
           <button onClick={() -> {}}>IOS</button>
         </div>
      )}
      {/* STEP 3 */}
      {this.state.activeStep === 3 && (
         <div>
           when did you buy it?
         </div>
      )}
  }
}

CodePudding user response:

I am a bit confused about your second comment but for the first comment you can wrap your buttons and render them based on a condition.

import React from "react";
class App extends React.Component {
  constructor() {
    super();
    this.state = { showMessage: false, os: "" };
  }

  _showMessage = (bool) => {
    this.setState({
      showMessage: bool
    });
  };

  _setOs = (value) => {
    this.setState({
      os: value
    });
  };

  render() {
    return (
      <div>
        Do you have a laptop <br />
        <button onClick={this._showMessage.bind(null, true)}>yes</button>
        <button onClick={this._showMessage.bind(null, false)}>no</button>
        {this.state.showMessage && <div>What kind of laptop?</div>}
        <br />
                // when user clicks yes, buttons will appear

        {this.state.showMessage === true && (
          <div>
            {/* I want to hide these buttons until the 'yes' button is clicked*/}
            <button onClick={this._setOs.bind(null, "Windows")}>Windows</button>
            <button onClick={this._setOs.bind(null, "IOS")}>IOS</button>
            <button onClick={this._setOs.bind(null, "")}>None</button>
          </div>
        )}
        {/* I want to display a third button which says none of the above */}

             // If use clicks windows or IOS, it will show him the next 
             //question. otherwise it wont show anything
        {!!this.state.os && <div>when did you buy it?</div>}
      </div>
    );
  }
}

export default App;

please explain your logic clearly so I can understand it and edit my answer and complete rest of your question.

CodePudding user response:

I'm not familiar with class based components but here is how I would go about creating a questionnaire. Note that I am using functional components.

First thing would be to create an object containing all of your questions, answers and possible outcomes for each step. Here is a quick example :

export const QuestionsAnswers = {
  1: {
    question: "Do you have a laptop",
    answers: [
      { answer: "Yes", nextStep: 2 },
      { answer: "No", nextStep: 3 },
    ],
  },
  2: {
    question: "What kind of laptop?",
    answers: [
      { answer: "Windows", nextStep: 5 },
      { answer: "IOS", nextStep: 5 },
    ],
  },
  3: {
    question: "Do you have a desktop?",
    answers: [
      { answer: "Yes", nextStep: 4 },
      { answer: "No", nextStep: 5 },
    ],
  },
  4: {
    question: "What OS does it have?",
    answers: [
      { answer: "Windows", nextStep: 5 },
      { answer: "IOS", nextStep: 5 },
    ],
  },
  5: {
    question: "Questions Over!",
    answers: [],
  },
};

Next would be to create a component that takes a step from your questions and answers object as props. This component will return the question text as well as loop over the options for the user to select. It will also take the setState function to set the next step :

const Question = ({ questions, setStep }) => {
  return (
    <div>
      <p>{questions.question}</p>
      {questions.answers.map((e) => {
        return <button onClick={() => setStep(e.nextStep)}>{e.answer}</button>;
      })}
    </div>
  );
};
export default Question;

Lastly, in the parent component I would declare the step state and render out the Question component. :

import "./styles.css";
import React from "react";
import Question from "./Question";
import { QuestionsAnswers } from "./QuestionsAnswers";

export default function App() {
  const [step, setStep] = React.useState(1);
  return (
    <div className="App">
      <h1>Question</h1>
      <Question questions={QuestionsAnswers[step]} setStep={setStep} />
    </div>
  );
}

With this sort of setup, you can easily extend / adjust your questions and your code will dynamically render what you need just based off your initial questions and answers object.

A codesandbox example : https://codesandbox.io/s/fast-field-vyqlr1?file=/src/QuestionsAnswers.js:0-690

  • Related