본문 바로가기

TIL(Today i learned)

[TIL-2022.09.26] nextjs image upload

오늘 한 일 : 

1.aws에 image 업로드하기 

2.image 업로드하는 컴포넌트 작성 

3.MDN으로 기초다지기 

 


리액트 렌더링 횟수 추적하기 

 

질문이 있다. 

import React, { useState } from 'react';
import { Modal } from 'src/components/atoms';
import { ImageUpload } from 'src/components/atoms';

export const CreateArticleModal = () => {
  const [imageUrl, setImageUrl] = useState<string>();

  return (
    <Modal>
      <ImageUpload setImageUrl={setImageUrl} />
    </Modal>
  );
};

 

/* eslint-disable @next/next/no-img-element */
import React from 'react';
import { useS3Upload } from 'next-s3-upload';
import { compressImage } from 'src/utils';
import { usePreview } from 'src/hooks';

interface Props {
  setImageUrl: (e: string) => void;
}

export const ImageUpload = ({ setImageUrl }: Props) => {
  const [preview, setPreview] = usePreview();
  const { FileInput, openFileDialog, uploadToS3 } = useS3Upload();

  const handleFileChange = async (file: File) => {
    setPreview(file);
    const compressedImage = await compressImage(file);
    const { url } = await uploadToS3(compressedImage);
    setImageUrl(url);
  };

  return (
    <div>
      <FileInput onChange={handleFileChange} />
      <button onClick={openFileDialog}>Upload file</button>
      {preview && <img src={preview} alt="preview image" />}
    </div>
  );
};

 

import React, { useState, useEffect, useMemo } from 'react';

export const usePreview = () => {
  const [file, setFile] = useState<File>();
  const [preview, setPreview] = useState<any>(); // NOTE : any 수정

  const reader = useMemo(() => {
    return new FileReader();
  }, []);

  useEffect(() => {
    if (file) {
      reader.readAsDataURL(file);
      reader.onloadend = () => {
        setPreview(reader.result);
      };
    }
  }, [reader, file]);

  return [preview, setFile] as const;
};

 

이런 구조로 되어있는 컴포넌트가 있다. 

이때 ImageUpload라는 컴포넌트에서 특정 파일을 선택하면 ImageUpload는 몇번 렌더링될까? 

 

우선 ImageUpload 에서 몇번 렌더링이 되는지 확인해보려고 콘솔을 찍어보았다. 그랬더니 4번 렌더링되고 있었다. 

왜 4번 렌더링이 되는 것일까? 이유가 궁금하다. 내 입장에서 저 친구는 4번 렌더링이 될 필요가 없다. 

 

Profiler에서 해당 컴포넌트가 왜 렌더링 되었는지 찾아준다. 그래서 확인해봤다. 

react profiler ImageUpload 컴포넌트 렌더링 원인 확인

아니 나는 렌더링이 되는 모든 원인을 찾아주는 줄 알았다. 그런데 왠걸, 하나밖에 알려주지 않는다. Hook 1 changed. 

그리고 그 밑에는 언제언제 렌더링이 되었는지 알려준다. 5.8, 5.8, 6, 6.1 이렇게 총 4번. 그런데 마지막에는 1.6ms가 걸린다. 

1.6ms가 걸리는걸 보니 아마도 이미지를 화면에 그리는 중인 것 같다. 

 

우선 저 Hook 1 changed는 뭘 말하는것일까? (처음에는 이것이 말하는 것이 훅이 1번 변경되었다고 말하는 것인줄 알았는데, 그게 아니라 1번 훅이 변경되었다는 말을 하는 것 같았다. 이렇게 생각한 이유는 아래에서 setPreview를 제거하고 확인했더니 Hook 6 changed라고 나왔기 때문이다.)

 

우선 렌더링을 일으키는 원인을 하나씩 차근차근 살펴보려고 한다. 

무엇이 렌더링을 일으키는지 찾아나가기 위해 내가 선택한 방법은 렌더링을 일으킬 것 같은 친구들을 하나씩 제거해보면서, 

렌더링이 줄어드는지 확인하는 것이었다. 

 

1.그렇게 발견한 친구 setPreview : 

이 친구를 잠깐 제거하면 렌더링이 2번 줄어든다. 

setPreview를 제거했더니 렌더링이 2번으로 줄었다

그럼 남아있는 2번은 무엇때문일까? 

 

2.upLoadToS3 함수 : 

의심되는 녀석은 uploadToS3함수이다. 아니나 다를까 이친구를 제거하니, 더이상 어떤 렌더링도 일어나지 않았다. 고로 이 친구로부터 렌더링이 2번 일어나고 있었던 것이다. 이 친구는 next-s3-upload라는 라이브러리에서 제공해주는 함수다. 그래서 내부를 살펴봤더니, 그곳에서 setState를 2번 사용하고 있었다. 아무래도 그래서 렌더링이 2번 일어난게 아닌가 싶다. 

이 함수에 대해선 렌더링을 줄이기가 쉽지 않을 것 같다. 그냥 이 라이브러리를 이용하지 말고 내가 직접 만들어서 사용하는 것도 방법일 것 같은데, 조금 더 고민이 필요하다. 

 

 

그러면 내가 컨트롤할 수 있는 부분은 setPreview이다. 이친구는 왜 2번이나 렌더링을 일으킨 것일까. 

사실 이 안에서 나는 2번 setState를 사용하고 있었다. 이것을 한번으로 줄일 수는 없을까? 

 

 

내가 알기로 useState는 batch update를 지원한다. 그런데 어떤 상황에서 batch update를 지원하는 것일까? 

https://jwookj.tistory.com/102

 

TIR ## 1 [React State Batch Update]

학습을 목적으로 Medium에서 읽은 글을 번역한 글입니다. 번역이 완벽하지 않을 수 있고, 직역하기보다는 문맥에 맞추어 자연스럽게 정리하려고 했습니다. 오류나, 개선하면 좋을 부분들에 대한

jwookj.tistory.com

이 글에 의하면 batch update는 동일한 event handler 안에 있을 때 동작하는 것 같다. 단순히 이 블로그여서라기 보다는, dan abramov가 한 말이기 때문에 신뢰가 가는 것 같다. 

 

 

batch와 관련된 내용은 조금 더 찾아봐야할 것 같다. 오늘 하루가 마무리 되어가고 있다. 

 

 


 

MDN으로 기초다지기 : 새롭게 알게된 것들 

 

- css를 만든 그룹 : https://www.w3.org/Style/CSS/

 

Cascading Style Sheets

Soft­ware Nearly all browsers nowadays support CSS and many other applications do, too. To write CSS, you don't need more than a text editor, but there are many tools available that make it even easier. Of course, all software has bugs, even after several

www.w3.org

 

- a태그에서 밑줄을 제거하면 접근성 점수에서 떨어질 수도 있다. 

 

- css 적용의 우선순위 : 

CSS 언어에는 충돌시 어떤 규칙이 이기는지 제어하는 규칙이 있습니다 — 이러한 규칙을 계단식(cascade) 및 우선 순위(specificity) 라고 합니다. 아래 코드 블록에서 p 선택자에 대해 두 가지 규칙을 정의했지만, 단락이 파란색으로 표시됩니다. 파란색으로 설정한 선언은 스타일 시트에서 나중에 나타나고 이후 스타일은 이전 스타일을 재정의 하기 때문입니다. 이것은 실제의 계단식 (cascade) 입니다.

그러나 기본적으로 더 구체적인 것이 이긴다. 그냥 p 태그보다는 class 선택자가 더 구체적이다. 때문에 동일한 p 태그를 가리키는 class 선택자가 위에 있고, p 태그 선택자가 아래에 있는 경우 class 선택자가 이길 것이다. 

 

 

- css에도 함수가 존재한다