I am having trouble setting up a state of my component. Kindly check the details as below
Codesandbox link – https://codesandbox.io/s/goofy-glade-z32zp
This is my App Component containing 4 sub components
import React, { useState } from "react"; import "./App.css"; import RadioType from "./components/Radio/RadioQuestion"; import CheckBox from "./components/Checkbox/CheckBox"; import SelectType from "./components/SelectBox/Selectbox"; import Slider from "./components/Slider/slider"; import data from "./components/jsonData/data.json"; const App = (props) => { const [values, setValues] = useState(); const setAnswerState = (details) => { let newState = []; if (values !== null && values !== undefined) newState = JSON.parse(JSON.stringify(values)); if (newState === null || newState === undefined) { newState = []; newState.push(details); } else { if ( newState.filter((x) => x.question_id === details.question_id).length === 0 ) newState.push(details); else { let indexOfFilteredObj = newState.indexOf( newState.filter((x) => x.question_id === details.question_id)[0] ); newState[indexOfFilteredObj] = details; } } setValues(JSON.parse(JSON.stringify(newState))); console.log(values) }; return ( <div className="App"> {JSON.stringify(values)} {data.map((v, i) => { return ( <div key={i}> {v.question_type === "radio" && ( <RadioType details={v} onChange={setAnswerState} /> )} {v.question_type === "checkbox" && ( <CheckBox details={v} onChange={setAnswerState} /> )} {v.question_type === "select" && ( <SelectType details={v} onChange={setAnswerState} /> )} {v.question_type === "slider" && ( <div style={{ marginLeft: "300px" }}> <Slider details={v} onChangeState={setAnswerState} /> </div> )} </div> ); })} </div> ); }; export default App;
Checkbox
import React, { useState } from "react"; const CheckBox = (props) => { const { details, onChange } = props; const [checkedValues, setCheckedValues] = useState([]); const setGlobalState = (value) => { let answer = value; let stateObj = { question_id: details.questionId, answers: answer, question_type: "checkbox", }; onChange(stateObj); }; return ( <div> <div>{details.question}</div> <label> {details.answers === undefined ? null : details.answers.map((checkBoxAnswers, index) => { return ( <div key={index}> <input type="checkbox" name={`checkbox_${details.questionId}`} value={checkBoxAnswers} onChange={(e) => { let currentValues = checkedValues; if (e.target.checked) currentValues.push(e.target.value); else { const index = currentValues.indexOf(e.target.value); if (index > -1) { currentValues.splice(index, 1); } } setCheckedValues(currentValues); setGlobalState(currentValues); }} /> <label key={index}>{checkBoxAnswers}</label> </div> ); })} </label> <br /> </div> ); }; export default CheckBox;
Radio
import React from "react"; const RadioType = (props) => { const { details, onChange } = props; const setGlobalState = (value) => { let answer = [value]; let stateObj = { question_id: details.questionId, answers: answer, question_type: "radio", }; onChange(stateObj); }; return ( <div> <div>{details.question}</div> <label> {details.answers === undefined ? null : details.answers.map((radioQuestionAnswers, index) => { return ( <div key={index}> <input type="radio" name={`radio_${details.questionId}`} value={radioQuestionAnswers} onChange={(e) => setGlobalState(e.target.value)} /> <label key={index}>{radioQuestionAnswers}</label> </div> ); })} </label> <br /> </div> ); }; export default RadioType;
Select
import React from "react"; const SelectType = (props) => { const { details, onChange } = props; const setGlobalState = (value) => { let answer = [value]; let stateObj = { question_id: details.questionId, answers: answer, question_type: "select", }; onChange(stateObj); }; return ( <> <div>{details.question}</div> <select name={`checkbox_${details.questionId}`} onChange={(e) => { setGlobalState(e.target.value); }} > {details.answers === undefined ? null : props.details.answers.map((selectAns, index) => { return ( <option key={index} value={selectAns}> {selectAns} </option> ); })} </select> </> ); }; export default SelectType;
NouiSlider
import React from "react"; import Nouislider from "nouislider-react"; import "nouislider/distribute/nouislider.css"; const Slider = (props) => { const { details, onChangeState } = props; const setGlobalState = (value) => { let answer = [value]; let stateObj = { question_id: details.questionId, answers: answer, question_type: "slider", }; onChangeState(stateObj); }; return ( <> <Nouislider style={{ color: "red", width: "600px" }} start={[0]} pips={{ mode: "count", values: details.division }} clickablePips range={{ min: details.range.min, max: details.range.max, }} onChange={(e) => { let valueOfSlider = parseFloat(e[0]); setGlobalState(valueOfSlider); }} /> </> ); }; export default Slider;
Coming to the problem whenever I try to set state from the radio checkbox or select it does set the state and updates correctly via setAnswerState method that is passed as prop to child. Whenever I try to change the slider the setAnswerState gets values as undefined or null, so the complete state that is set by other child components is lost, I am not able to find the reason behind state lost.
Here is the sample data I used for testing
[ { "question": "When was the Cilivar War?", "question_type": "radio", "answers": ["1877-1866", "1877-1872", "1877-1851", "1877-1880"], "questionId": "099011" }, { "question": "World's Largest country by population?", "answers": ["China", "Canada", "United kingdom", "India"], "correctAns": "China", "question_type": "checkbox", "dependent_question_id": [ { "question_id": "099011", "answers_to_match": [ { "operator": "AND", "answers": ["1877-1866"] } ] } ], "questionId": "0990758" }, { "question": "Where is the Tajmahal?", "answers": ["Agra", "Mumbai", "Pune", "Punjab"], "correctAns": "Agra", "question_type": "select", "dependent_question_id": [ { "question_id": "099011", "answers_to_match": [ { "operator": "AND", "answers": ["1877-1866"] } ] }, { "question_id": "099078", "answers_to_match": [ { "operator": "AND", "answers": ["Canada", "United kingdom"] } ] } ], "questionId": "099096" }, { "questionId": "0002346", "question_type": "slider", "division": 5, "range": { "min": 0, "max": 100 } } ]
Advertisement
Answer
Just add []
in useState()
as shown below:
const [values, setValues] = useState([]);
And then update the setAnswerState
method to:
const setAnswerState = (details) => { // below statement will handle both the cases: // updating an existing question as well as adding in a new question setValues((prevValues) => [ ...prevValues.filter((x) => x.question_id !== details.question_id), { ...details } ]); };