状态未按要求设置(React、Hooks)

State Not Getting Set As Required (React, Hooks)

我在设置组件状态时遇到问题。请查看以下详细信息

Codesandbox link - https://codesandbox.io/s/goofy-glade-z32zp

这是我的应用程序组件,包含 4 个子组件

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;

复选框

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;

电台

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;

每当我尝试从单选复选框或 select 设置状态时都会遇到问题,它确实设置了状态并通过作为 prop 传递给子项的 setAnswerState 方法正确更新。每当我尝试更改滑块时,setAnswerState 获取的值为 undefined 或 null,因此其他子组件设置的完整状态丢失,我无法找到状态丢失背后的原因。

这里是我用来测试的样本数据

[
  {
    "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
      }
    
  }
]

只需在useState()中添加[],如下图:

const [values, setValues] = useState([]);

然后将setAnswerState方法更新为:

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 }
  ]);
};

在你的应用组件中,你需要在 useState() 中添加 [] as

const [values, setValues] = useState([]);

在 setAnswerState() 内部,使用 newState 作为 setValues() 的值。

setValues(newState)

没有

setValues(JSON.parse(JSON.stringify(newState)));