[React] useState( )로 배열 추가하기_2탄 (feat.일기장)

Hyun·2022년 1월 5일
3

React

목록 보기
8/22
post-thumbnail

일기장을 <DiaryEditor/>자식 컴포넌트(작성폼)에서 작성한 일기데이터를 저장하면 <DiaryList/>자식 컴포넌트(일기리스트)가 렌더링하고있는 일기리스트 배열에 추가해주고싶은데, React에서 같은레벨끼리는 데이터를 주고받을 수 없다.

그래서 State끌어올리기를 이용하여 적용할것이다.
State끌어올리기,단방향 데이터 흐름,역방향 이벤트 흐름을 이용해서
DiaryEditor에 배열을 이용한 리액트의 List에 아이템(=일기)을 동적으로 추가하는 예제를 다뤄볼 것이다.

🎯코딩 순서 정리

1. 부모컴포넌트인 App.js에 가서 useState를 써야한다.
2. 상태변화함수(setState)는 작성폼인 DiaryEditor.js에 가서 줘야한다.
3. state는 일기리스트인 DiaryList.js에 줘야한다.

그럼 DiaryEditor.js에서 새로운 일기가 작성되면 상태변화함수가 부모컴포넌트로 전달되어 새로운 state를 DiaryList.js에 추가되어 렌더링이 된다.


📖예제

1. App.js

(전에 썼던 dummyList는 지워주고, React의 useState기능을 쓴다.
= 상단에 import { useState } from 'react';를 꼭 명시해야한다는 말)

import {  useRef, useState } from 'react';   
//리액트의 useRef, useState기능을 쓸거에요
import './App.css';                       //css를 입히려면 App.css파일로 연동
import DiaryEditor from "./DiaryEditor";  //DiaryEditor 자식요소를 쓸거에요
import DiaryList from "./DiaryList"       //DiaryList 자식요소를 쓸거에요
 
const App = () => {
  const [data,setData] = useState([]);
  const dataId = useState(0);
  const onCreate = (author,content,emotion) => {
    const created_date = new Date().getTime();
    const newItem = {
      author,
      content,
      emotion,
      created_date,
      id : dataId.current
    };
    dataId.current += 1;
    //dataId.current는 0이라는 값을 가짐, 값을 한번쓰면 1씩 아이디가 증가
    setData([newItem, ...data])
    //원래배열에 있던 데이터를 스트레드연산자로 쓰고, 새로운데이터를 newItem을 앞에 추가
  };
  return (
    <div className="App">
      <DiaryEditor onCreate={onCreate} />
      <DiaryList diaryList={data} />
    </div>
  );
}

export default App;

<코드설명>

1) const [data,setData] = useState([]); = (전역) 나는 일기배열을 저장할것이므로 배열[]로 초기값을 저장함.
(*왜 배열이냐하면 = 일기에는 작성자,내용,감정점수 등 여러 리스트가 있으므로 하나의 배열로 묶여서 [{작성자:@@@},{내용:@@@},{감정점수:@@@},{날짜:@@@},{id:@@}] 이렇게 저장이되어야한다.)

2) const dataId = useRef(0); = 앞서 map()에서 Key가 필요한 이유를 배웠다. 그럼 하나의 배열에는 하나의 고유한 id가 있어야하므로 id를 초기값0부터 부여한다.
변수처럼 사용해야하기때문에 useRef를 사용해서 만들어주었다.
(=React기능이므로 상단에 import { useRef } from "react";명시할것)

👉🏻[내생각]
고유한key는 마치 사람으로따지면 주민번호같은 존재이고, 50명의 사람(배열들)에게 배식을 하려고하면(=추가,삭제,수정) 제대로 배식이이루어졌는지 주민번호(key)로 확인하는 느낌으로 와닿는다.

3) const onCreate = (author,content,emotion) => {
const created_date = new Date().getTime();
const newItem = {author, content, emotion, created_date, id : dataId.current
};
dataId.current += 1;
setData([newItem, ...data])
};

=일기배열에 새로운 data(일기배열)를 추가할 onCreate를 만든다.
작성폼에 작성할 author,content,emotion을 onCreate함수가 받아서 1)의 data에 업데이트시키는 로직을 setData를 이용해서 onCreate함수 안에 작성한것
= onCreate는 파라미터로 (author,content,emotion)를 받고, 현재시간은 만들어주고, 새로운아이템으로 추가되어야할값은 {author, content, emotion, created_date, id : dataId.current
}이다.
(*dataId.current는 2번의 초기값인 0을 가지고있다.)
newItem으로 추가될 값을 다 명시하고 중괄호를 닫은 다음 생각을해보면, dataId에 +1을 시행하지않으면 dataId는 항상0이되므로 고유한값이 아니게된다.
그래서 dataId.current += 1;을 수행하게 해준다.
결과적으로 onCreate가 시행이되면 마지막에 dataId +1을 해주므로 고유한값이 되게 된다.
setData로 [새로추가 = newItem, 원래있던 data들=...data]상태변화를 명시해준다.
(만약 새로추가될 일기를 끝에 추가하고싶으면 두개의 자리를바꾸면된다.)

4) <DiaryEditor onCreate={onCreate} /> = 3번의 일기데이터를 추가 할 수 있는 함수를 DiaryEditor(작성폼)에 prop으로 전달한다.

5) <DiaryList diaryList={data} /> = 1번의 기존데이터를 DiaryList(일기리스트)에 prop으로 전달한다. (=렌더링)


2. DiaryEditor.js

import { useRef, useState } from "react";

const DiaryEditor = ({onCreate}) => {
    const  [state, setState] = useState({
        author : "",
        content : "",
        emotion : 1,
    });
    
    const authorInput = useRef();
    const contentTextarea = useRef();

    const handleChangeState = (e)=>{
        setState({
        ...state,
        [e.target.name] : e.target.value,
    });
};
    const handleSubmit = ()=>{
        if (state.author.length < 1){
            authorInput.current.focus();
            return;
        }
        if (state.content.length < 5){
            contentTextarea.current.focus();
            return;
        }
        //props로 받은 onCreate를 호출 (저장될 내용들)
        onCreate(state.author, state.content, state.emotion);
        alert("저장성공");
        //저장이되면 상태는 초기값으로 재설정함
        setState({
            author: "",
            content: "",
            emotion: 1,
        });
    };


    return <div className="DiaryEditor">
        <h2>오늘의 일기</h2>
        <div>
            <input 
            ref={authorInput}
            name="author"
            value={state.author} 
            onChange={handleChangeState}
            />
        </div>

        <div>
            <textarea 
            ref={contentTextarea}
            name="content"
            value={state.content} 
            onChange={handleChangeState}
            />
        </div>

        <div>
            <select 
            name="emotion" 
            value={state.emotion} 
            onChange={handleChangeState}>
                <option value={1}>1</option>
                <option value={2}>2</option>
                <option value={3}>3</option>
                <option value={4}>4</option>
                <option value={5}>5</option>
            </select>
        </div>

        <div>
            <button onClick={handleSubmit}>저장하기</button>
        </div>
    </div>
};

export default DiaryEditor;

<코드설명>

1)const DiaryEditor = ({onCreate}) => { const [state, setState] = useState({ author : "", content : "", emotion : 1, });
=App.js에서 onCreate를 prop으로 내려줬으니까, prop으로 전달받아야한다.
(모르겠으면 [React] State, Props)

2)const handleSubmit = ()=>{
onCreate(state.author, state.content, state.emotion);
alert("저장성공");
setState({author: "", content: "", emotion: 1});
};
= props로 받은 onCreate를 호출하고, 작성폼에서 저장될 내용들(state.author, state.content, state.emotion)을 넣어준다.
if문에 성립하여 저장이되면, 알림을 띄워준 후 setState를 이용해서 상태는 초기값으로 재설정한다.


🎯한눈에 로직 정리


(made by.hyun👩🏻‍💻)


일기장 결과


작성 안한상태

작성 후 저장하기 누른상태

일기리스트에 추가된 상태


🚀참고자료

React강의-이정환강사

profile
FrontEnd Developer (with 구글신)

0개의 댓글