下面React代码示例的目的是创建渐进式表单,该表单一开始只显示一个问题,然后在用户单击按钮时显示下一个问题(同时保持前一个问题可见(。我写的实际代码包含12个问题,它们的数量、内容和顺序可能会随着时间的推移而变化。目前,代码可以工作,但它很长,很难更新,所以我相信必须有一种更好、更动态的方法来做到这一点。我尝试过的一种方法是创建一个sperate.js文件,其中包含每个问题的变量数组;渐进的";表单使用的方面是方法。
如有任何想法或建议,我们将不胜感激!
import React, { useState, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import classes from './InputForm2.module.css';
const InputForm2 = () => {
const dateOfBirthInputRef = useRef();
const membershipTypeInputRef = useRef();
const dateOfJoiningInputRef = useRef();
let navigate = useNavigate();
function routeChange() {
let path = '/results';
navigate(path);
}
function dataHandler() {
const enteredDateofBirth = dateOfBirthInputRef.current.value;
const enteredMembershipType = membershipTypeInputRef.current.value;
const enteredDateOfJoining = dateOfJoiningInputRef.current.value;
const inputData = {
dateOfBirth: enteredDateofBirth,
membershipType: membershipTypeRef,
dateOfJoining: enteredDateOfJoining,
};
console.log(inputData);
}
function submitHandler(event) {
event.preventDefault();
dataHandler();
routeChange();
}
const [q2IsOpen, setQ2IsOpen] = useState(false);
const [q3IsOpen, setQ3IsOpen] = useState(false);
const btn1ClickHandler = (event) => {
event.preventDefault();
setQ2IsOpen(true);
};
const btn2ClickHandler = (event) => {
event.preventDefault();
setQ3IsOpen(true);
};
const btn3ClickHandler = (event) => {
event.preventDefault();
setQ4IsOpen(true);
};
return (
<div className={classes.formbox}>
<form>
<section className={`${classes.active}`}>
<div className={classes.textbox}>
<b>Question 1</b>
<p>What is your date of birth?</p>
<input
className={classes.input}
type="date"
required
ref="dateOfBirthInputRef"
></input>
</div>
<div className={classes.btn__container}>
<button className={classes.button} onClick={btn1ClickHandler}>
Next
</button>
</div>
</section>
<section className={`${q2IsOpen ? classes.active : classes.inactive}`}>
<div className={classes.textbox}>
<b>Question 2</b>
<p>
What is your membershiptype?
</p>
<select
className={classes.input}
required
ref="membershipTypeInputRef"
>
<option></option>
<option value="Platinum">Platinum</option>
<option value="Gold">Gold</option>
<option value="Basic">Basic</option>
</select>
</div>
<div className={classes.btn__container}>
<button className={classes.button} onClick={btn2ClickHandler}>
Next
</button>
</div>
</section>
<section className={`${q3IsOpen ? classes.active : classes.inactive}`}>
<div className={classes.textbox}>
<b>Question 3</b>
<p>What date did you start your membership?</p>
<input
className={classes.input}
type="date"
required
ref="dateOfJoiningInputRef"
></input>
</div>
<div className={classes.btn__container}>
<button className={classes.button} onClick={btn3ClickHandler}>
Next
</button>
</div>
</section>
<div className={classes.btn__container}>
<button
className={`${classes.submitbutton} ${
q4IsOpen ? classes.active : classes.inactive
}`}
onClick={submitHandler}
>
Calculate
</button>
</div>
</form>
</div>
);
};
export default InputForm2;
这不是完全可以工作的代码,只是一个如何构建它的想法。正如你自己建议的那样,制作一系列问题对象是个好主意。你也可以把问题结构分解成它自己的组成部分:
const Question = ({thisIndex, currentIndex, title, text, ref, handler}) => {
return(
<section className={`${thisIndex >= currentIndex-1 ? classes.active : classes.inactive}`}>
<div className={classes.textbox}>
<b>{title}</b>
<p>{text}</p>
<input
className={classes.input}
type="date"
required
ref=ref
></input>
</div>
<div className={classes.btn__container}>
<button className={classes.button} onClick={handler}>
Next
</button>
</div>
</section>
)
}
输入到Question
组件的道具可以从QUESTIONS
对象数组映射,假设对象结构类似于{title: 'Question 1', text: 'Why are we here?', //and so on}
。我只需跟踪主表单中最后一个已回答问题的索引,并将其传递给数组中的每个问题,就可以跟踪可见性——这样,只有当前一个问题得到回答时,它才会变得可见。
const InputForm2 = () => {
const [currentIndex, setCurrentIndex] = useState(0);
//all your other code
const handler = (i) => {
setCurrentIndex(i)
//do more stuff
}
const questions = QUESTIONS.map((question, i) => {
return(
<Question key={i}
thisIndex=i currentIndex={currentIndex}
title={question.title} text={question.text}
handler={handler(i)}
//and so on
/>
)
});
return (
<div>{questions}</div>
)
}
然后,在您的表单中,您可以返回组件的questions
数组。
编辑
以类似的方式,由于您对不同的问题有不同类型的输入/选择,您可以制作单独的组件,并将其作为道具传递给您的问题。
const QSelector = ({options}) => {
const optionElements = options.map((option, i) => {
return(
<option //get your data from option element
)
})
return(
<selector>
{options}
</selector>
)
}
显然,对于三种不同的输入类型和三个问题,这并不是非常有用,但当你进入时,如果你有5个选择器q,5个输入,你会发现你可以重用很多结构,只需传递任何不同的数据。
下面,我将更新"问题"组件,将其作为"答案"道具接收。
const Question = ({thisIndex, currentIndex, title, text, ref, handler, answer}) => {
return(
<section className={`${thisIndex >= currentIndex-1 ? classes.active : classes.inactive}`}>
<div className={classes.textbox}>
<b>{title}</b>
<p>{text}</p>
{answer}
</div>
<div className={classes.btn__container}>
<button className={classes.button} onClick={handler}>
Next
</button>
</div>
</section>
)
}