DEVELOP
article thumbnail

인프런 이정한님의 한입크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지 ] 강의 수강 후 강의의 내용을 정리하며 공부한 것을 쓴 게시글입니다.

 

한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지 - 인프런 | 강의

개념부터 독특한 프로젝트까지 함께 다뤄보며 자바스크립트와 리액트를 이 강의로 한 번에 끝내요. 학습은 짧게, 응용은 길게 17시간 분량의 All-in-one 강의!, - 강의 소개 | 인프런...

www.inflearn.com


React에서 사용자 입력 처리하기

- DiaryEditor 컴포넌트가 필요한 것 

  • 작성자
  • 일기본문 
  • 감정 점수

- 작성자, 일기 본문, 감정 점수를 state로 저장하고 변경한다. 

- 하나의 state로 객체 배열을 관리할 수 있다. 

- 초기값은 빈 문자열과 1로 설정한다. 

  const [state, setState] = useState({
    author: "",
    content: "",
    emotion: 1
  });

- setState를 할 때에는 spread 연산자(...)를 이용해, 바꾸고자 하는 것을 제외하고는 원본을 유지한다. 

- [e.target.name]: e.target.value 

      ->  state배열 원소 중  e.target.name 의 값을 key로  가진 객체의 value값을 e.target.value로 바꾼다. 

  const handleChangeState = (e) => {
    setState({
      ...state,
      [e.target.name]: e.target.value
    });
  };

- onChange : value 변화를 감지

- onClick : Click Event 감지

- 작성자

        <input
          name="author"
          value={state.author}
          placeholder="author"
          onChange={handleChangeState} />

- 일기 본문

        <textarea
          name="content"
          value={state.content}
          placeholder="content"
          onChange={handleChangeState} />

- 감정 점수

        <span>오늘의 감정점수 : </span>
        <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>

- 저장 버튼 

<button onClick={handleSubmit}>저장</button>

일기 작성 폼


React에서 DOM 조작하기

# DiaryEditor.js

-  useRef로 특정 DOM 선택하기

  const authorInput = useRef();
  const contentInput = useRef();

 

- input 태그와 textarea 태그 각각에 ref={authorInput}, ref={contentInput} 추가 

 

- handleSubmit 함수 수정 

- 작성자 이름이 1글자 미만이면 저장되지 않고, 작성자 이름 입력 칸으로 focus

- 일기 본문이 5글자 미만이면, 저장되지 않고, 일기 본문 입력 칸으로 focus

  const handleSubmit = () => {
    if (state.author.length < 1) {
      authorInput.current.focus();
      return;
    }

    if (state.content.length < 5) {
      contentInput.current.focus();
      return;
    }
    alert("저장 성공!");
  }

작성자가 1글자 미만일 때 작성자 입력 칸으로 focus
내용이 5글자 미만일 때 내용 입력 칸으로 focus


React에서 배열 사용하기 (CRUD)

# App.js 

- 일기 리스트를 저장할 배열 data - state로 사용 

  const [data, setData] = useState([]);

- 각각의 일기의 아이디 값을 저장할 dataId - ref로 사용 

 

  const dataId = useRef(0);

- 일기 생성 시 호출 할 함수 : onCreate 

   - 새로운 객체를 생성하고, 기존 배열에 새로운 객체를 포함하여 setData 함 
   - DiaryEdit 호출 시 onCreate 함수를 전달 :  <DiaryEditor onCreate={onCreate} />

   - 기존 저장 버튼을 눌렀을 때 실행되던 함수에 onCreate 추가해 data를 저장하게 함

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

일기 저장후 리스트 생성된 화면

- 일기 삭제 시 호출할 함수 : onRemove

    - 삭제 할 일기의 id를 targetId로 전달받아 해당 id의 객체를 제외한 나머지 객체들로 새 객체 생성 해 setData

  const onRemove = (targetId) => {
    const newDiaryList = data.filter((it) => it.id !== targetId);
    setData(newDiaryList);
  };

- 일기 수정 시 호출할 함수 : onEdit 

  - 수정 할 일기의 id를 targetId로 전달받고, map으로 배열을 돌면서  해당 id의 객체의 content를 전달받은 newContent 값으로 바꿈

  const onEdit = (targetId, newContent) => {
    setData(
      data.map((it) =>
        it.id === targetId ? { ...it, content: newContent } : it
      )
    );
  };

    - DiaryList 호출 시 onRemove 함수와 onEdit 함수를 전달하고, DiaryList에서 DiaryItem을 호출할 때 두 함수를 넘겨 받음

     <DiaryList onRemove={onRemove} onEdit={onEdit} diaryList={data} />
     <DiaryItem key={it.id} {...it} onRemove={onRemove} onEdit={onEdit} />

# DiaryList.js

- 전달받은 diaryList 를 map으로 돌며, 각각의 일기의 DiaryItem을 생성 

const DiaryList = ({ onRemove, onEdit, diaryList }) => {
  return (
    <div className="DiaryList">
      <h2>일기 리스트</h2>
      <h4>{diaryList.length}개의 일기가 있습니다.</h4>
      <div>
        {diaryList.map((it) => (
          <DiaryItem key={it.id} {...it} onRemove={onRemove} onEdit={onEdit} />
        ))}
      </div>
    </div>
  );
};

# DiaryItem.js

- 수정작업 중일 때를 뜻하는 isEdit -  state로 사용하고, 기본 값은 false

- toggleEdit 함수는 toggle 처럼 isEdit이 true값일때는 false로, false 값일 때는 true 값으로 바꿈

  const [isEdit, setIsEdit] = useState(false);
  const toggleIsEdit = () => setIsEdit(!isEdit);

- 수정 중인 일기의 내용의 값인 localContent - state로 사용 

  const [localContent, setLocalContent] = useState(content);

- 삭제 버튼 클릭하면 호출되는 함수 : handleRemove 

    - 사용자에게 삭제할 것인지 물어보고, 확인을 클릭하면 App.js에서 선언한 onRemove 함수 호출

  const handleRemove = () => {
    if (window.confirm(`${id + 1}번째 일기를 삭제하시겠습니까?`)) {
      onRemove(id);
    }
  };

일기 삭제

- 수정 버튼을 클릭하고, 수정 후 완료 벼튼을 클릭하면 호출되는 함수 : handleEdit

    - 사용자가 수정한 내용의 글자 수가 5 미만이라면, 해당 입력 칸에 focus하여 다시 입력하도록 함

    - 사용자에게 수정할 것인지 물어보고, 확인 버튼을 클릭하면, App.js에서 선언한 onEdit 함수 호출 

    - isEdit을 다시 false로 바꾸도록 toggleEdit 함수 호출  

  const handleEdit = () => {
    if (localContent.length < 5) {
      localContentInput.current.focus();
      return;
    }

    if (window.confirm(`${id + 1}번째 일기를 수정하시겠습니까?`)) {
      onEdit(id, localContent);
      toggleIsEdit();
    }
  };

일기 수정 완료

- 일기 수정 중에 (수정)취소 버튼 클릭하면 호출 되는 함수 : handleQuitEdit 

   - isEdit을 false로 바꾸고, 화면에 보이는 일기의 내용을 원래의 값으로 다시 보여지도록 함 

  const handleQuitEdit = () => {
    setIsEdit(false);
    setLocalContent(content);
  };

일기 수정 취소

- 수정 중임을 나타내는 isEdit의 값이 true일 때는 textarea로 수정할 수 있도록 하고, false일 때는, 해당 일기의 content값이 보여지도록 함 

      <div className="content">
        {isEdit ? (
          <>
            <textarea
              ref={localContentInput}
              value={localContent}
              onChange={(e) => setLocalContent(e.target.value)}
            />
          </>
        ) : (
          <>{content}</>
        )}
      </div>

- isEdit이 true이면 (수정)취소, (수정)완료 버튼이 보여지도록 하고, false이면 삭제, 수정 버튼이 보여지도록 함 

      {isEdit ? (
        <>
          <button onClick={handleQuitEdit}>취소</button>
          <button onClick={handleEdit}>완료</button>
        </>
      ) : (
        <>
          <button onClick={handleRemove}>삭제</button>
          <button onClick={toggleIsEdit}>수정</button>
        </>
      )}

 

profile

DEVELOP

@JUNGY00N