React/게시판만들기 v1.

[React][CRUD] 리액트로 간단한 게시판 페이지 만들기 - 19. Refactoring, useState 구문 useSelector 로 클린코딩하기

binaryJournalist 2020. 11. 19. 22:43
반응형

 

 

목차로 돌아가기: binaryjourney.tistory.com/pages/ReactCRUD-create-board-tutorial

 

[React][CRUD] create-board-tutorial

* 인용 시 출처 같이 기재부탁드립니다. code: github.com/jwlee-lnd/react-create-board jwlee-lnd/react-create-board Description(korean) : https://binaryjourney.tistory.com/pages/ReactCRUD-create-board-..

binaryjourney.tistory.com

 

 

 

 

 

렌더링 최적화를 위해 useState로 사용했던 

 

 

 

const [TitleValue, setTitleValue] = useState("")
const [ContentValue, setContentValue] = useState("")

 

 

 

요 useState 구문을 useSelector를 이용하여 코드도 줄이고 reducer를 재활용하는 방법과 렌더링 최적화를 실천해보겠다.

 

 

 

 

 

 

useSelector를 이용한다는 것은 redux-toolkit의 createSlice로 만든 slice에 initialState 로 이미 객체변수가 존재함을 전제로 한다.

 

 

 

 

 

내가 리팩토링하려는 RegisterPage 를 보면 이미 useSelector로 initialState를 다 가져다 놓은 상태여서 정말 아주 조금의 편집만 하는 정도이다.

 

// RegisterPage.js

import React, { useEffect, useState } from "react";
import { shallowEqual, useDispatch, useSelector } from "react-redux";
import RegisterOrEdit from "./Sections/RegisterOrEdit";
import { articleActions } from "../../../slice/articleSlice";

function RegisterPage(props) {
  const dispatch = useDispatch();

  const { id, views, date, editDate, title, content } = useSelector(
    (state) => ({
      id: state.articleReducers.id,
      views: state.articleReducers.views,
      date: state.articleReducers.date,
      editDate: state.articleReducers.editDate,
      title: state.articleReducers.title,
      content: state.articleReducers.content,
    }),
    shallowEqual
  );
  
.
.
.
}

 

 

 

 

setTitleValue 와 setContentValue를 사용한 메소드를 찾아 지워주고

 

 

다음과 같이 바꿔준다.

 

 

일단 작성만 해놓고 저장은 하지 말고 잠시만 기다려주길 바란다.

 

 

 

// RegisterPage.js

  const onTitleChange = (event) => {
    const { name, value } = event.target;
    dispatch(articleActions.changeRegisterInput({ name: name, value: value }));
  };

  const onContentChange = (event) => {
    const { name, value } = event.target;
    dispatch(articleActions.changeRegisterInput({ name: name, value: value }));
  };

 

 

 

 

그리고 articleActions 를 export 하는 articleSlice로 가서 reducer에 다음 항목을 추가한다.

 

 

 

// articleSlice.js

    changeRegisterInput: (state, { payload }) => {
      switch (payload.name) {
        case "title":
          return {
            ...state,
            title: payload.value,
          };

        case "content":
          return {
            ...state,
            content: payload.value,
          };

        default:
          break;
      }
    },

 

 

 

두 코드블럭을 해석해보면 같은 action 함수에서 name이 title인지 content인지 가려서 onChange 이벤트가 발생했을 때의 value를 state에 반영해준다.

 

 

 

 

 

그리고 RegisterPage에서 TitleValue 와 ContentValue가 쓰인 곳을 useSelector로 잡아온 title 과 content로 바꿔준다.

 

 

 

// RegisterPage.js

function RegisterPage(props) {

...  
    if (title === "" || title === null || title === undefined) { // 수정
      alert("제목을 작성하십시오.");
      return false;
    }

    if (content === "" || content === null || content === undefined) { // 수정
      alert("내용을 작성하십시오.");
      return false;
    }

...

    if (IsForUpdate) {
      dispatch(articleActions.updateArticle(article));
    } else {
      dispatch(articleActions.registerArticle(article));
    }
  };

  return (
    <>
      <RegisterOrEdit
        titleValue={title} // 수정
        contentValue={content} // 수정
        handleTitleChange={onTitleChange}
        handleContentChange={onContentChange}
        handleSubmit={onSubmitArticle}
        updateRequest={IsForUpdate}
      />
    </>
  );
}

 

 

 

 

RegisterPage 의

 

 

const [IsForUpdate, setIsForUpdate] = useState(false);

 

 

부분은 initialState에 없기 때문에 지우면 안된다.

이건 필요하다.

 

 

 

 

더 클린코딩을 해보자면 RegisterPage의

 

  const onTitleChange = (event) => {
    const { name, value } = event.target;
    dispatch(articleActions.changeRegisterInput({ name: name, value: value }));
  };

  const onContentChange = (event) => {
    const { name, value } = event.target;
    dispatch(articleActions.changeRegisterInput({ name: name, value: value }));
  };

 

dispatch(articleActions.changeRegisterInput({ name: name, value: value }));

 

이 부분이 반복됨을 알 수 있다.

 

 

원래는 title과 content가 서로 다르게 사용될 수도 있을 때를 고려하여 onChange 메소드를 각각 만든 것인데

 

 

지금은 크게 상관이 없으므로

 

 

다음과 같이 합쳐주기로 한다.

 

 

  const onRegisterChange = (event) => {
    const { name, value } = event.target;
    dispatch(articleActions.changeRegisterInput({ name: name, value: value }));
  };

 

 

 

그리고 RegisterPage의 컴포넌트 return 부분 메소드도

 

  return (
    <>
      <RegisterOrEdit
        titleValue={title}
        contentValue={content}
        handleRegisterChange={onRegisterChange} // 수정
        handleSubmit={onSubmitArticle}
        updateRequest={IsForUpdate}
      />
    </>
  );

 

이렇게 한 줄로 합쳐주고

 

 

property 이름이 변경됐기 때문에

 

RegisterOrEdit 으로 가서 바꿔줘야 한다.

 

 

      <form onSubmit={props.handleSubmit}>
        <br />
        <div style={{ width: "80%", margin: "2rem auto" }}>
          <label>Title: </label>
          <Input
            onChange={props.handleRegisterChange} // 변경
            value={props.titleValue}
            type="text"
            name="title"
          />
          <hr></hr>
          <TextArea
            rows="30"
            onChange={props.handleRegisterChange} // 변경
            value={props.contentValue}
            name="content"
          />
        </div>
        <Button type="primary" onClick={props.handleSubmit}>
          {props.updateRequest ? "수정" : "등록"}
        </Button>
      </form>

 

 

이렇게 같은 액션 함수와 같은 메소드를 쓰는 onChange 이벤트로 바뀌게 되었다.

 

 

 

 

다음은 redux-saga의 select를 이용한 refactoring 을 해보겠다.

 

 

 

 

 

+) 추가

 

개발자창에 오류가 보여서 추가로 수정한다.

 

ArticleDetail 컴포넌트에 tbody 태그를 추가하겠다. 그리고 colspan 도 colSpan으로 수정한다. 이거는 JSX 변환 문제 때문인 것 같다.

 

 

// ArticleDetail.js

          <tbody> {/* 추가  */}
            <tr>
              <th>번호</th>
              <td>{props.id}</td>
              <th>조회수</th>
              <td>{props.views}</td>
            </tr>
            <tr>
              <th>날짜</th>
              <td>{new Date(props.date).toLocaleString()}</td>
            </tr>
            <tr>
              <th>제목</th>
              <td colSpan="3">{props.title}</td> {/* 수정 */}
            </tr>
            <tr>
              <th>내용</th>
              <td colSpan="3">{props.content}</td> {/* 수정 */}
            </tr>
          </tbody> {/* 추가  */}

 

 

 

목차로 돌아가기:  binaryjourney.tistory.com/pages/ReactCRUD-create-board-tutorial

 

[React][CRUD] create-board-tutorial

* 인용 시 출처 같이 기재부탁드립니다. code: github.com/jwlee-lnd/react-create-board jwlee-lnd/react-create-board Description(korean) : https://binaryjourney.tistory.com/pages/ReactCRUD-create-board-..

binaryjourney.tistory.com

 

반응형