如何简化这段React代码?(渐进式输入形式)



下面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>
)

}

最新更新