I've created two components which together create a 'progressive' style input form. The reason I've chosen this method is because the questions could change text or change order and so are being pulled into the component from an array stored in a JS file called QuestionsText
So far I've been trying to add a data handler function which will be triggered when the user clicks on the 'Proceed' button. The function should collect all of the answers from all of the rendered questions and store them in an array called InputData. I've managed to get this to work in a hard coded version of InputForm using the code shown below but I've not found a way to make it dynamic enough to use alongside the Question component. Can anybody help me make the dataHander function collect data dynamically?
dataHander function and variables:
const dateOfBirthInputRef = useRef();
const firstNameInputRef = useRef();
const surnameInputRef = useRef();
function dataHandler() {
const enteredDateofBirth = dateOfBirthInputRef.current.value;
const enteredFirstName = firstNameInputRef.current.value;
const enteredSurname = surnameInputRef.current.value;
const inputData = {
dateOfBirth: enteredDateofBirth,
firstName: enteredFirstName,
surname: enteredSurname,
};
console.log(inputData);
}
InputForm component:
import React, { useState, useRef } from "react";
import { Link, useNavigate } from "react-router-dom";
import Question from "./Question";
import QuestionsText from "../../assets/data/QuestionsText";
import classes from "./InputForm.module.css";
const InputForm = (props) => {
const [currentIndex, setCurrentIndex] = useState(1);
const handler = (thisIndex) => {
if (thisIndex === currentIndex) {
setCurrentIndex(currentIndex 1);
}
};
const maxIndex = QuestionsText.length;
const questions = QuestionsText.map((question) => {
return (
<Question
key={question.id}
ref={question.id}
thisIndex={question.index}
currentIndex={currentIndex}
maxIndex={maxIndex}
text={question.text}
type={question.type}
clickHandler={() => handler(question.index)}
/>
);
});
return (
<form className={classes.formbox}>
<div>{questions}</div>
<div className={classes.btn__container}>
<button
className={`${classes.submitbutton} ${
currentIndex >= maxIndex ? classes.active : classes.inactive
}`}
>
Proceed
</button>
</div>
</form>
);
};
export default InputForm;
Question component:
import React from "react";
import classes from "./InputForm.module.css";
const Question = (props) => {
return (
<section
className={`${
props.thisIndex <= props.currentIndex
? classes.active
: classes.inactive
}`}
>
<div className={classes.textbox}>
<p>{props.text}</p>
{(() => {
switch (`${props.type}`) {
case "date":
return (
<input className={classes.input} type="date" required></input>
);
case "number":
return (
<input
className={classes.input}
type="number"
min="1"
step="any"
required
/>
);
}
})()}
</div>
<div className={classes.btn_container}>
<button
type="button"
className={`${classes.button} ${
props.thisIndex < props.currentIndex ? classes.disabled : ""
}
${props.thisIndex === props.maxIndex ? classes.inactive : ""}`}
onClick={props.clickHandler}
>
Next
</button>
</div>
</section>
);
};
export default Question;
CodePudding user response:
There what I have done:
https://codesandbox.io/s/angry-dew-37szi2?file=/src/InputForm.js:262-271
So, we can make it easier, you just can pass necessary data when call handler from props:
const inputRef = React.useRef();
const handleNext = () => {
props.clickHandler(props.reference, inputRef.current.value);
};
And merge it at InputForm component:
const [inputData, setInputData] = useState({});
const handler = (thisIndex) => (key, value) => {
if (thisIndex === currentIndex) {
setCurrentIndex(currentIndex 1);
setInputData((prev) => ({
...prev,
[key]: value
}));
}
};
// ...
<Question
// ...
clickHandler={handler(question.index)}
/>
So, you wanted array (object more coninient I think), you can just save data like array if you want:
setInputData(prev => [...prev, value])
Initially, I thought you want to collect data on button clicks in the InputForm, but apparently you can do without this, this solution is simpler