I have DATA
- array of objects. Each object has answers and their isCorrect boolean prop that defines whether that options is truthy or not.
I collect each option correctness in isCorrect
state and then show correct answers by changing border-color.
How to make tag controlled and reset its value after a button click in this scenario?
const DATA = [
{
sentenceFirstPart: "It takes a lot of",
sentenceSecondPart: "to learn how to waterski properly",
answerOptions: [
{ answerText: "", isCorrect: false },
{ answerText: "attempt", isCorrect: false },
{ answerText: "effort", isCorrect: true },
{ answerText: "trial", isCorrect: false },
{ answerText: "try", isCorrect: false }
]
},
{
sentenceFirstPart: "It was Thomas Edison who ",
sentenceSecondPart: "electricity",
answerOptions: [
{ answerText: "", isCorrect: false },
{ answerText: "detected", isCorrect: false },
{ answerText: "invented", isCorrect: true },
{ answerText: "found", isCorrect: false },
{ answerText: "discovered", isCorrect: false }
]
}
];
export default function App() {
const [isCorrect, setIsCorrect] = useState({});
const [isChecked, setIsChecked] = useState(false);
const handleValueChange = (value, index) => {
setIsCorrect((prev) => ({
...prev,
[index]: value === "true" ? true : false
}));
};
return (
<Wrapper>
{DATA.map((sentence, index) => (
<Sentence
isChecked={isChecked}
isCorrect={isCorrect[index]}
key={index}
>
<span>
{index 1}. {sentence.sentenceFirstPart}
</span>
<select onChange={(e) => handleValueChange(e.target.value, index)}>
{sentence.answerOptions.map((option, index) => (
<option value={option.isCorrect} key={index}>
{option.answerText}
</option>
))}
</select>
<span>{sentence.sentenceSecondPart}</span>
</Sentence>
))}
<div>
<button onClick={() => setIsChecked(true)}>Check</button>
<button>Reset</button>
</div>
</Wrapper>
);
}
const Wrapper = styled.div`
display: flex;
flex-direction: column;
gap: 1rem;
button {
padding: 0rem 1rem;
width: 6rem;
}
`;
export const Sentence = styled.div`
display: flex;
align-items: center;
span {
font-size: 1.2rem;
}
select {
margin: 0 0.5rem;
border: 1px solid;
padding: 0.2rem;
border-radius: 4px;
font-weight: 500;
border-color: ${({ isChecked, isCorrect }) =>
!isChecked ? "currentColor" : isCorrect ? "green" : "red"};
}
`;
CodePudding user response:
Since the select
in posted code is not controlled I think it would be suitable to create reference of these with useRef
and reset the values.
Forked demo with modification: codesandbox
Create an array ref and handling function for reset:
const selectsRef = useRef([]);
const handleReset = () => {
setIsChecked(false);
setIsCorrect({});
selectsRef.current.forEach((item) => {
if (!item) return;
item.value = "";
});
};
Assign the ref
for each select
in the output to create reference:
<Wrapper>
{DATA.map((sentence, index) => (
<Sentence isChecked={isChecked} isCorrect={isCorrect[index]} key={index}>
<span>
{index 1}. {sentence.sentenceFirstPart}
</span>
<select
ref={(node) => (selectsRef.current[index] = node)}
onChange={(e) => handleValueChange(e.target.value, index)}
>
{sentence.answerOptions.map((option, index) => (
<option value={option.isCorrect} key={index}>
{option.answerText}
</option>
))}
</select>
<span>{sentence.sentenceSecondPart}</span>
</Sentence>
))}
<div>
<button onClick={() => setIsChecked(true)}>Check</button>
<button onClick={handleReset}>Reset</button>
</div>
</Wrapper>
CodePudding user response:
You can simply get a selection of the inputs and place an onClick event handler on the reset button itself. Then set It's value as nothing.
Here's the forked sandbox with the updates made. https://codesandbox.io/s/bold-hypatia-tkprkc
The function I used to reset the values:
const resetApp = () => {
const selects = document.querySelectorAll('Select');
selects.forEach(select => {
select.value = "";
});
}
for the button, the function is called here:
<button onClick={() => resetApp()}>Reset</button>