• Feed
  • Explore
  • Ranking
/
/
    React

    React 배열 다루기 (기초)

    ReactuseStatesetStatearraymaptsxTypescriptonChange
    전
    전상욱
    2025.04.10
    ·
    4 min read

    1. 가상의 데이터 타입 정의

    data.d.ts

    interface Survey {
      ASK_SQ: number;
      ASK_CN: string;
      ANSWER_LIST: {
        ANSWER_SQ: number;
        ANSWER_CN: string;
      }[];
      ANSWER: null | string | number;
    };

    2. 가상의 데이터 정의

    data.ts

    export const defaultList: Survey[] = [
      {
        ASK_SQ: 1,
        ASK_CN: "질문1",
        ANSWER: null,
        ANSWER_LIST: [
          { ANSWER_SQ: 1, ANSWER_CN: "보기 항목1" },
          { ANSWER_SQ: 2, ANSWER_CN: "보기 항목2" },
          { ANSWER_SQ: 3, ANSWER_CN: "보기 항목3" },
          { ANSWER_SQ: 4, ANSWER_CN: "보기 항목4" },
          { ANSWER_SQ: 5, ANSWER_CN: "보기 항목5" },
        ],
      },
      {
        ASK_SQ: 2,
        ASK_CN: "질문2",
        ANSWER: null,
        ANSWER_LIST: [
          { ANSWER_SQ: 6, ANSWER_CN: "보기 항목1" },
          { ANSWER_SQ: 7, ANSWER_CN: "보기 항목2" },
          { ANSWER_SQ: 8, ANSWER_CN: "보기 항목3" },
          { ANSWER_SQ: 9, ANSWER_CN: "보기 항목4" },
          { ANSWER_SQ: 10, ANSWER_CN: "보기 항목5" },
        ],
      },
      {
        ASK_SQ: 3,
        ASK_CN: "질문3",
        ANSWER: null,
        ANSWER_LIST: [
          { ANSWER_SQ: 11, ANSWER_CN: "보기 항목1" },
          { ANSWER_SQ: 12, ANSWER_CN: "보기 항목2" },
          { ANSWER_SQ: 13, ANSWER_CN: "보기 항목3" },
          { ANSWER_SQ: 14, ANSWER_CN: "보기 항목4" },
          { ANSWER_SQ: 15, ANSWER_CN: "보기 항목5" },
        ],
      },
      {
        ASK_SQ: 4,
        ASK_CN: "질문4",
        ANSWER: null,
        ANSWER_LIST: [
          { ANSWER_SQ: 16, ANSWER_CN: "보기 항목1" },
          { ANSWER_SQ: 17, ANSWER_CN: "보기 항목2" },
          { ANSWER_SQ: 18, ANSWER_CN: "보기 항목3" },
          { ANSWER_SQ: 19, ANSWER_CN: "보기 항목4" },
          { ANSWER_SQ: 20, ANSWER_CN: "보기 항목5" },
        ],
      },
      {
        ASK_SQ: 5,
        ASK_CN: "질문5",
        ANSWER: null,
        ANSWER_LIST: [],
      },
    ];

    3. 화면 출력

    App.tsx

    import { FormEvent, useCallback, useEffect, useState } from "react";
    import { Survey, defaultList } from "./data";
    
    export default function App() {
      const [list, setList] = useState<Survey[]>([]);
    
      // 데이터 조회
      const getList = async () => {
        setList(defaultList);
      };
    
      // 데이터 변경
      const changeList = (ASK_SQ: number, ANSWER: string | number) => {
        // 일반.. (솔팅할 필드가 없어도 됨)
        setList((prev) => {
          const result = prev?.map((item) => {
            if (item?.ASK_SQ !== ASK_SQ) return item;
            return { ...item, ANSWER };
          });
          return result;
        });
    
        // 솔팅할 필드가 있을 때..
        // setList((prev) => {
        //   let copy = [...prev];
        //   let find = copy?.find((x) => x?.ASK_SQ === ASK_SQ) as Survey;
        //   let other = copy?.filter((x) => x?.ASK_SQ !== ASK_SQ);
        //   find = { ...find, ANSWER };
        //   let result = [...other, find];
        //   result = result?.sort((a, b) => a?.ASK_SQ - b?.ASK_SQ);
        //   return result;
        // });
      };
    
      // 데이터 저장
      const onSubmit = (e: FormEvent<HTMLFormElement>) => {
        e?.preventDefault();
    
        const result = list?.map((x) => ({ ASK: x?.ASK_SQ, ANSWER: x?.ANSWER }));
    
        const askTxt = `설문 내용을 저장하시겠습니까?
          
    ${result?.map((x) => `질문 ${x?.ASK} - 답변 ${x?.ANSWER}`)?.join("\n")}`;
        let ask = window?.confirm(askTxt);
        if (!ask) return;
    
        alert("전송이 완료되었습니다.");
        console.log(result);
        getList();
      };
    
      // 타입 (객관식/주관식)
      const getType = useCallback((ask: Survey) => {
        return (ask?.ANSWER_LIST?.length ? "객" : "주") + "관식";
      }, []);
    
      // 초기 실행
      useEffect(() => {
        getList();
      }, []);
    
      return (
        <form onSubmit={onSubmit}>
          <h1>설문지</h1>
    
          <ul>
            {list?.map((ask) => (
              <li key={ask?.ASK_SQ}>
                <h3>
                  {ask?.ASK_CN} ({getType(ask)})
                </h3>
                <ol>
                  {!ask?.ANSWER_LIST?.length ? (
                    <input
                      required
                      type="text"
                      value={ask?.ANSWER ?? ""}
                      onChange={(e) => {
                        changeList(ask?.ASK_SQ, e?.target?.value);
                      }}
                    />
                  ) : (
                    ask?.ANSWER_LIST?.map((answer) => (
                      <li key={answer?.ANSWER_SQ}>
                        <input
                          required
                          type="radio"
                          name={"ASK_" + ask?.ASK_SQ}
                          id={"ANSWER_" + answer?.ANSWER_SQ}
                          checked={ask?.ANSWER === answer?.ANSWER_SQ}
                          onChange={() => {
                            changeList(ask?.ASK_SQ, answer?.ANSWER_SQ);
                          }}
                        />
                        <label htmlFor={"ANSWER_" + answer?.ANSWER_SQ}>
                          {answer?.ANSWER_CN}
                        </label>
                      </li>
                    ))
                  )}
                </ol>
              </li>
            ))}
          </ul>
    
          <button>저장</button>
        </form>
      );
    }

    4. 결과 확인

    4958

    저장 버튼 클릭 시 화면







    - 컬렉션 아티클