[React][인스타그램] 리팩토링 - 코드 되짚어보기 (코드 포맷 고치기)

GY·2021년 12월 23일
0

리액트

목록 보기
31/54
post-thumbnail

👑 네이밍

💎 네이밍

submitLoginInfo
send보다 submit을 사용하면 폼에 있는 데이터를 백엔드 서버로 보낸다는 의미를 더 함축적으로 전달할 수 있다.
LoginInfo : 어떤 정보를 보내는지를 포함할 수 있다.

💎 더 정확한 변수명을 써주자

before
    const regex = new RegExp('@');
    const validId = regex.exec(emailInputVal);
    if (validId && pwInputVal.length >= 5) {
      setValidState(true);
    } else {
      setValidState(false);
    }
after
    const emailValidatorReg = new RegExp('@');
    const validId = emailValidatorReg.exec(emailInputVal);
    if (validId && pwInputVal.length >= 5) {
      setValidState(true);
    } else {
      setValidState(false);
    }

💎 어떤 기능을 하는지 의미를 담은 변수를 지정하자

before
    if (validId && pwInputVal.length >= 5) {
      setValidState(true);
    } else {
      setValidState(false);
    }
after
    const isFormValid = validId && pwInputVal.length >= 5;

    setValidState(isFormValid);

💎 regex 네이밍

emailValidatorReg = new RegExp();

const isFormValid = validId && pwInputVal.length >=5;
setValidstate(isFormValid)

ref

function handleInput(e) {
  const {name, vlaue} = e.target;


👑 불필요한 변수 제거

💎 조건부 클래스명 변경

className={`button ${isActive ? '' : 'inactive'}`}

💎 disabled

disabled = {!isValid}
feeds && feeds[0].map


👑 comment

💎 계산된 속성명

function handleuserInput(event){
	const {name, value} = event.target;
	setUserInput({...userInput, [name]: value});
  
}

[name]을 해주는 이유는, 고정값이 아닌 바뀌는 값이기 때문에 계산된 속성명을 사용하는 것이다.

💎 addComment

before
  function addComment(e) {
    e.preventDefault();
    let updated = comments;
    const newCommentVal = commentRef.current.value;
    updated = [
      ...updated,
      { id: uuid(), commentId: myId, commentText: newCommentVal },
    ];
    setComments(updated);
    commentRef.current.value = '';
  }
after
  function addComment(e) {
    e.preventDefault();
    const newComment = {
      id: uuid(),
      commentId: myId,
      commentText: newCommentVal,
    };
    const newCommentVal = commentRef.current.value;

    setComments([...comments, newComment]);
    commentRef.current.value = '';
  }

💎 deleteComment

before
  function deleteComment(comment) {
    const updated = comments;
    const filtered = updated.filter(com => {
      return com.id !== comment.id;
    });
    setComments(filtered);
  }
after
  • filter는 새로운 배열을 반환하기 때문에 굳이 새로운 배열을 복사해서 만들어줄 필요가 없다. 원본배열이 변경되지 않기 때문이다.
  • filtered보다는 의미가 더 명확한 filteredComments로 써주자/
  function deleteComment(comment) {
    const filteredComments = comments.filter(com => {
      return com.id !== comment.id;
    });
    setComments(filteredComments);
  }

💎 handleText()

before
function handleTextContent(text) {
    if (text.length > 30) {
      text = text.slice(0, 30);
      return (
        <>
          <p>{text}</p>
          <button className="more-text">...더보기</button>
        </>
      );
    } else {
      return text;
    }
  }
        <div className="textContent">{handleTextContent(feed.textContent)}</div>
after

  function showMore(text) {
    return (
      <>
        <p>{text.slice(0, 30)}</p>
        <button className="more-text">...더보기</button>
      </>
    );
  }
        <div className="textContent">
          {feed.textContent.length > 30
            ? showMore(feed.textContent)
            : feed.textContent}
        </div>


👑 불필요한 state 사용 지양하기

💎 state

다른 state를 가지고 계산 가능한 것은 state가 아니다.

const [isActive, setIsActive] = useState(false)
//다른 state나 props를 가지고 계산되는 것은 state로 쓸 필요 없다.
//불필요하게 복잡해지기 때문이다.
//이미 state가 있기 때문에, 다음과 같이 그저 변수로만 계산한 값을 할당해 만들어주면 된다.
const isActive = id.includes('@') && password.length > 4;


💎 props로 전달받은 값 state에 저장하는 것은 지양하자.

Feed({feedData}) {
  const [comments, setComments] = useState([...feedData.commentList]);
  //state가 각각 따로 놀게 되는 위험이 있다.
  //전달받은 props를 그대로 수정해주는 것이 좋다.

const handleFeedComment = (feedId, comment) => {
  setFeeds(prevFeeds => {
  return prevFeeds.map(prevFeed => {
    if(prevFeed.id === feed.id) {
      return {...prevFeed, comment: comment};
    }
    return prevFeed;
  });
});
  setFeeds(nextFeeds)
}

💎 ref

ref는 값을 수정해도 렌더링을 하지 않음
ref는 하나로 사용해 객체형태로 사용해도 좋다.
굳이 렌더링을 하지 않아도 될 때는 ref값을 사용하는 것이 좋다.


💎 불필요한 삼항 연산자는 없애자

before
          <button
            disabled={validState ? false : true}
after

          <button
            disabled={!validState}

💎 불필요한 조건부 렌더링

before
function MainGayun() {
  const [stories, setStories] = useState();
  async function loadStories() {
    const data = await (
      await fetch('http://localhost:3000/data/Gayun/story.json')
    ).json();
    setStories(data);
  }

  useEffect(() => {
    loadStories();
  }, []);

  return (
    <div className="main-gayun">
      <Nav />
      <Story stories={stories} />
      <div className="main-content">
        <Feeds />
        {stories && <SideBar stories={stories} />}
after

Sidebar가 꼭 데이터가 들어온 뒤 나중에 보여야 하는게 아니라면, SideBar 내부에서 처리를 해주는 것이 더 적절하다.
그러나 state 초기값을 빈 배열로 준다면 이것 또한 필요없다.
초기값이 빈배열이므로 빈 상태로 스토리의 내부를 채우고, 이후에 state 업데이트 되어 값이 채워졌을 때 리렌더링 되어 스토리 안의 컨텐츠가 다시 표시되기 때문이다.



👑 key props

💎 key props 고유한 id 값 지정하기 (uuid, map 2nd param)

고유값을 만들어주는 라이브러리를 사용했는데, 이것은 렌더링 시마다 각기 다른 값을 생성하기 때문에 불필요하다.
map의 두번째 인자로 index를 키값으로 주는 방법도 생각해봤는데, 이 방법 또한 인덱스를 키 값으로 주는 것이기 때문에 삭제및 추가의 상황에서 적절하지 않다.

데이터 내부에 아이디로 지정할만한 값이 포함되어 있지 않을 때 사용할 최선의 방법이 있을 것이라고 생각했는데, 데이터에서 고유한 값을 아이디로 지정하는 것이 가장 좋은 선택지였다.



Reference

profile
Why?에서 시작해 How를 찾는 과정을 좋아합니다. 그 고민과 성장의 과정을 꾸준히 기록하고자 합니다.

0개의 댓글