簡體   English   中英

在 React 中,我如何設置問題表單並運行用戶可以單擊的不同答案框?

[英]In React how do I set up a question form and run different answer-boxes that a user can click?

我創建了一個類似結構的表格,供用戶選擇一個框,然后像這樣單擊下一步(下面的所有圖片)。 我使用地圖來顯示框,當單擊下一步時,我正在使用狀態加載下一個答案框。 我還有一個標題,我在地圖上方有一個普通的 p-tag。 我對此進行測試的方法是使用一個計數器(也是狀態對象),每次單擊下一個時我都會遞增。 但是問題存儲在數組中(se 代碼測試),我不知道如何實現這一點,以便我可以有一個流程和工作方式讓標題和問題數組在我單擊下一步時顯示。 我正在考慮以某種方式使用道具,但我似乎無法弄清楚該怎么做。 現在我可以遍歷一個數組(帶標題)並在 qboxes 中顯示答案,但是當我想自動添加下一個時,我無法以任何流暢的方式進行。

在此處輸入圖像描述

在此處輸入圖像描述 (點擊 qbox-answer 並點擊下一步按鈕)

代碼:

//For looping through and have qboxes created. 
const testAnswers1 = ["answer 1", "answer 2", "answer 3", "answer 4", "answer 5", "answer 6"];
const testAnswers2 = ["answer 1", "answer 2", "answer 3", "answer 4", "answer 5", "answer 6"];
const testAnswers3 = ["answer 1", "answer 2", "answer 3", "answer 4", "answer 5", "answer 6"];

//Every array should have one title displayed until end
const questionTitles = ["title1", "title2", "title3", "title4"]



function ReportForm(props){

  const [title, setTitle] = useState(titles);
  const [qBoxes, setqBoxes] = useState(test);
  //const [isMouseOver, setMouseOver] = useState(false);

  //counter for title and qboxes
  let [counter, setCounter] = useState(0);
  //For storing answers
  let [answers, setAnswers] = useState([]);

  
//Code for handling hovering over an answerbox (css) and also collect the clicked answer

const handleClick = (event) => {

 
  if(event.currentTarget.classList.contains('active')) {
    event.currentTarget.classList.remove('active');

    answers.pop(event.currentTarget.value);
    

    
    console.log(event.currentTarget.value);
    
  } else {
    event.currentTarget.classList.add('active');

    setAnswers([...answers, event.target.value]);

    
  }
event.preventDefault();


}


//Next button code


const submitNext = (event) => {

  if (counter < titles.length -1){

    
      setqBoxes(qboxes[counter]);
      setCounter(counter = counter +1);
      setTitle(event.target.value);


  } else {
    //resets counter to last value so nothing happens when next is clicked
    setCounter(counter);
  }
 
}


//Code for map function

return (

    <div>
        <p>{questionTitles[counter]}</p>
        {qBoxes.map((e) => {

          return (
            <button
              
              onClick={handleClick}
              className="boxStyle"
              name="contentYes"
              value={e}
              onchange={handleChange}
              
            >{e}</button>
          )

        })};

        <button className="buttonNext" onClick={submitNext}>Next</button>
        <button className="buttonPrev" onClick={submitPrev}>Previous</button>


    </div>
  );

使用預構建的表單處理庫時,這些事情會變得容易得多。 查看FormikReact-Hook-Form

對於向導本身,考慮將每個問題(帶有答案數組)包裝在一個單獨的組件中,這樣它就不會看到其他問題或被其他問題打擾。

這是一個非常明確的方法:每個問題都是它自己的組件(你可以從一個數組中映射它們),並且它們由父級包裝,父級的工作是知道用戶在向導中的位置,已經回答了什么, 並只顯示當前問題。

包裝紙

首先,Wrapper 可以使用一個狀態來記住它當前在向導中的位置

const increment = (x) => x + 1;
const decrement = (x) => x - 1;

const Wizard = ({ children }) => {
const maxCount = React.Children.count(children) - 1;
  const minCount = 0;

  const [current, setCurrent] = React.useState(minCount);

  const incrementCurrent = () => setCurrent(increment);
  const decrementCurrent = () => setCurrent(decrement);
  const isMaxCount = current === maxCount;
  const isMinCount = current === minCount;

...

然后,它可以選擇對應於該狀態的子組件

...

return (
    <fieldset className="wizard">
      <legend>{name}</legend>

      {React.Children.toArray(children).at(current)}

      <button type="button" disabled={isMinCount} onClick={decrementCurrent}>
          prev
      </button>
      <button type="button" disabled={isMaxCount} onClick={incrementCurrent}>
          next
      </button>
    </fieldset>
)

你可以和任何孩子一起嘗試

<Wizard name="my wizard">
  <span>how</span>
  <span>YOU</span>
  <span>doin'</span>
</Wizard>

添加表單處理庫

如果我們使用一個庫來幫助我們在類似表單的情況下處理用戶輸入,一切都會變得更容易。 它可能需要某種初始化,因此我們也在父級中執行此操作,並確保傳遞子級(問題組件)將需要的任何控件或注冊函數。 在這個例子中,我使用了 React-Hook-Form

const form = useForm();

const onSubmit = () => {
   console.log(form.getValues())
}

return (
    ...
      <form onSubmit={form.handleSubmit(onSubmit)}>
        {React.cloneElement(React.Children.toArray(children).at(current), { form })}
    ...

在問題組件中接收表單處理程序

每個問題現在都可以使用該表單道具並與表單互動

例如文字輸入

const DescribeMarcellus = ({ form }) => (
    <article>
      <h2>Describe what Marsellus Wallace looks like</h2>
      <input type="text" {...form.register('description')} />
    </article>
  )

或者像你一樣的按鈕


const WhichCountry = ({ form }) => (
  <article>
    <h2>What country you from?</h2>
    <div className="flexCenter">
    {["What", "Tobleronistan", "Option 3"].map((ans) => (
      <div
        key={ans}
        className="option"
        style={{
          backgroundColor: form.getValues("country") === ans ? "blue" : "green"
        }}
        onClick={() => form.setValue("country", ans)}
      >
        {ans}
      </div>
      
    ))}
    </div>
  </article>
);

const SayWhatAgain = ({ form }) => (
  <article>
    <h2>
      <i>{form.getValues("country")}</i> ain't no country I ever heard of! They
      speak English in What?
    </h2>
    {["Yeah", "Nah"].map((ans) => (
      <div key={ans}>
        <input
          type="radio"
          id={ans}
          name="contact"
          value={ans}
          {...form.register("english")}
        />
        <label htmlFor={ans}>{ans}</label>
      </div>
    ))}
  </article>
);

把它們放在一起:

import React from "react";
import { useForm } from "react-hook-form";
import "./styles.css";

const increment = (x) => x + 1;
const decrement = (x) => x - 1;

const Wizard = ({ name, children }) => {
  const maxCount = React.Children.count(children) - 1;
  const minCount = 0;
  const [current, setCurrent] = React.useState(minCount);
  const incrementCurrent = () => setCurrent(increment);
  const decrementCurrent = () => setCurrent(decrement);
  const isMaxCount = current === maxCount;
  const isMinCount = current === minCount;

  const form = useForm();

  const onSubmit = () => {
    console.log(form.getValues());
  };

  return (
    <fieldset className="wizard">
      <legend>{name}</legend>
      <form onSubmit={form.handleSubmit(onSubmit)}>
        {React.cloneElement(React.Children.toArray(children).at(current), {
          form
        })}
        <button type="button" disabled={isMinCount} onClick={decrementCurrent}>
          prev
        </button>
        <button type="button" disabled={isMaxCount} onClick={incrementCurrent}>
          next
        </button>
        <button type="submit">submit</button>
      </form>
    </fieldset>
  );
};

const DescribeMarcellus = ({ form }) => (
  <article>
    <h2>Describe what Marsellus Wallace looks like</h2>
    <input type="text" {...form.register("description")} />
  </article>
);

const WhichCountry = ({ form }) => (
  <article>
    <h2>What country you from?</h2>
    <div className="flexCenter">
    {["What", "Tobleronistan", "Option 3"].map((ans) => (
      <div
        key={ans}
        className="option"
        style={{
          backgroundColor: form.getValues("country") === ans ? "blue" : "green"
        }}
        onClick={() => form.setValue("country", ans)}
      >
        {ans}
      </div>
      
    ))}
    </div>
  </article>
);

const SayWhatAgain = ({ form }) => (
  <article>
    <h2>
      <i>{form.getValues("country")}</i> ain't no country I ever heard of! They
      speak English in What?
    </h2>
    {["Yeah", "Nah"].map((ans) => (
      <div key={ans}>
        <input
          type="radio"
          id={ans}
          name="contact"
          value={ans}
          {...form.register("english")}
        />
        <label htmlFor={ans}>{ans}</label>
      </div>
    ))}
  </article>
);

export default function App() {
  return (
    <div className="App">
      <Wizard name="my wizard">
        <DescribeMarcellus />
        <WhichCountry />
        <SayWhatAgain />
      </Wizard>
    </div>
  );
}

codeSanbox 鏈接: https ://codesandbox.io/s/simple-wizard-sspt9u?file=/src/App.js

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM