react에서 axios로 받아온 map리스트에 radio버튼을 적용하는 방법

이무헌·2022년 11월 2일
0

react

목록 보기
7/19

먼저 결과를 저장하는 오브젝트배열은 다음과 같다.

export interface postTestResultType{
  content:string;
  score:string

}

최종 데이터를 저장하는 state

  const [postTestResult, setPostTestResult] = useState<postTestResultType[]>([]);

가장 먼저 정해야 할 것은 다음과 같다.
1.라디오버튼

const RadioButton = ({ value, onChange }: { value: any; onChange: any }) => {
    return (
      <label>
        <input
          type="radio"
          checked={value}
          onChange={onChange}
          style={{ zoom: "2.0" }}
        />
      </label>
    );
  };

2.이 라디오버튼을 감싸는 컨테이너

 const RadioGroup = ({ content, i }: { content: any; i: number }) => {
    const [chekedData, setCheckedData] = React.useState("");

    const handleChange = (value: any, score: string) => {
      setResult(content, score);
      setCheckedData(value);
    };

    return (
      <div
        style={{
          width: "142px",
          display: "flex",
          justifyContent: "space-evenly",
        }}
      >
        <RadioButton
          value={chekedData === `1`}
          onChange={() => {
            handleChange(`1`, "1");
          }}
        />
        <RadioButton
          value={chekedData === `2`}
          onChange={() => {
            handleChange(`2`, "2");
          }}
        />
        <RadioButton
          value={chekedData === `3`}
          onChange={() => {
            handleChange(`3`, "3");
          }}
        />
        <RadioButton
          value={chekedData === `C`}
          onChange={() => {
            handleChange(`C`, "C");
          }}
        />
      </div>
    );
  };

map으로 10개의 리스트를 불러온다 하면 radiogroup은 10개가 생성되며, 그 안에 chekedData 에 대한 state를 선언하였으므로 체크 표시는 공유되지 않는다.
중요한 onchange 함수이다.

const handleChange = (value: any, score: string) => {
      setResult(content, score);
      setCheckedData(value);
    };

결과를 저장하는 setResult,라디오 버튼에서 체크여부를 판단할 때 필요한
chekedData를 변경할 수 있는 setCheckedData hook

setResult는 다음과 같이 동작한다.

// 결과저장
let resultArray: postTestResultType[] = Array();
// filter함수를 위한 임시 똑같은 임시 변수
let newArray: any;

const setResult = (content: string, score: string) => {
    if (resultArray.length === 0) {
      resultArray.push({ content: content, score: score });
    } else {
      if (
        resultArray.find((a) => {
          return a.content === content;
        })
      ) {
        newArray = resultArray.map((a) => {
          return a.content === content ? {...a,score:score} : a;
        });
        resultArray = [...newArray];
      } else {
        resultArray.push({ content: content, score: score });
      }
    }
    console.log(resultArray);
  };

처음 선택했을 때 빈 배열이라면 일단 resultArray를 push한다.
(똑같은 stack배열인데 concat을 안 한 이유는 concat은 새로운 배열을 반환하므로 return을 해줘야하기 때문에 push를 사용하였다.또한 길이를 판별하는 이유는 빈 배열일 경우에 find나 map함수가 동작하지 않는다....왜인지는 모르겠다.)
만약 기존 배열에 content가 존재한다면 filter를 사용하여 임시 배열 newArray에 map함수를 이용하여 score를 바꾼 새로운 배열을 임시저장한다. 다시 resultArray에 얕은복사(채-신 ES6문법 spread)를 한다.
아니라면 그냥 push만 해준다.
이제 이 배열을 state에 저장하자. state는 비동기적이라 setCheckedData와 동시에 setPostTestResult를 동작시켜버리면 당연히 오류가 뜬다(not iterator부터 property오류가 대표적)그러므로 useEffect훅을 사용하여

setCheckedData로 인한 리랜더링->마운트->함수 생성및 뷰 표시

에서 마운트시 setPostTestResult를 동작시키면 된다.

  useEffect(() => {
    setPostTestResult(resultArray);
  }, [resultArray]);

마지막 파라미터를 꼭 넣어서 마운트되게 하자

-끝-

profile
개발당시에 직면한 이슈를 정리하는 곳

0개의 댓글

관련 채용 정보