반응형

React를 새로 생성했을 때 발생했던 에러입니다.

One of your dependencies, babel-preset-react-app, is importing the "@babel/plugin-proposal-private-property-in-object" package without declaring it in its dependencies. This is currently working because "@babel/plugin-proposal-private-property-in-object" is already in your node_modules folder for unrelated reasons, but it may break at any time. babel-preset-react-app is part of the create-react-app project, which is not maintianed anymore. It is thus unlikely that this bug will ever be fixed. Add "@babel/plugin-proposal-private-property-in-object" to your devDependencies to work around this error. This will make this message go away.

 

처음에는 Stack overflow에 나와있는 방법으로 해결을 했었습니다.

 

$ npm install --save-dev @babel/plugin-proposal-private-property-in-object

 

그런데 계속해서 뜨는게 거슬려서 확실하게 하고자 뭐가 문제인지 더 찾아봤습니다.

 

해결방법

여러 글들을 찾아다니다보니 npm과 create-react-app의 버전 호환 충돌일 가능성이 있다는 내용들이 있었습니다.

그래서 npm을 최신버전으로 올려주었더니 오류가 사라지는걸 확인할 수 있었습니다.

$ npm install -g npm@latest

 

 

반응형
반응형

react-native-vector-icons 사용하는 방법입니다.

Mac 기준입니다.

( icon 하나 사용하는데 하루가 걸린 기분이 듭니다... )

 

npm

$ npm install react-native-vector-icons
$ npm install -D @types/react-native-vector-icons

 

저는 typescript를 사용하고 있기 때문에 @types 부분도 추가했습니다.

 

 

iOS에서 아이콘 추가하기

 

1. 프로젝트를 열고 터미널을 열어줍니다.

$ cd ios
$ pod install

 

ios로 들어간다음 pod install을 해줍니다.

 

2. 프로젝트 폴더에서 ios -> project-name.xcworkspace를 열어줍니다. ( 대기 ! )

 

3. 다시 프로젝트 폴더에서 node_modules -> react-native-vector-icons -> Fonts 폴더를 복사합니다.

 

4. 아까 대기시켜둔 workspace에 project-name 폴더 아래에 복사한 Fonts폴더를 추가해줍니다.

추가할 때 아래 창이 뜨면 이렇게 해주면 됩니다.

 

아래처럼 추가된 모습을 볼 수 있습니다.

 

5. Fonts폴더를 추가시키고 아래를 보면 Info파일이 있습니다.

Info로 들어가서 아래처럼 내용들을 추가해줍니다.

Informations Property List
 - Fonts provided by application
   - item 0 ~ item 18 ( value에 폰트 내용을 추가합니다. )

 

Informations Property List 옆에 +를 누르고 Fonts provided by application을 추가합니다. ( 자동완성 )

Fonts provided by application 옆에 +를 누르고 item들을 추가시킨다음 Fonts내부에 ttf파일들 이름을 추가시켜줍니다.

 

추가를 하고난다음 Info를 닫고 프로젝트에서 ios -> project-name -> Info.plist파일을 열어보면 아래처럼 추가된 내용을 확인 할 수 있습니다.

 

workspace에서 project-name 폴더에 Build Phases -> Copy Bundle Resources를 확인해보면 여기도 Fonts가 추가된 것을 확인 할 수 있습니다.

 

이렇게 완료하고 ios를 재시작하면 icon이 들어오는 것을 확인 할 수 있습니다.

( 아이콘 추가방법을 가장 아래 추가해 두었습니다. )

 

 

Android에서 아이콘 추가하기

 

1. android/app/build.gradle 파일로 이동해서 아래 내용을 추가해줍니다.

apply from: file("../../node_modules/react-native-vector-icons/fonts.gradle")

 

2. android/settings.gradle 파일로 이동해서 아래 내용을 추가해줍니다.

include ':react-native-vector-icons'
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')

 

3. 다시한번 android/app/build.gradle 파일로 이동해서 아래 내용을 추가해줍니다.

dependencies {
    implementation project(':react-native-vector-icons')
    ...
}

 

dependencies 내부에 추가해줍니다.

 

4. gradlew clean를 실행합니다.

$ cd android
$ ./gradlew clean

 

pod install 한것과 같습니다.

 

이렇게 iOS, 안드로이드 모두 아이콘을 추가할 준비가 됐습니다.

 


 

아이콘 추가하기

react-native-vector-icons 바로가기

 

위 사이트에 접속하면 아래처럼 빨간배경에 제목과 아이콘 이름들을 확인 할 수 있습니다.

제목은 import할 때 사용하고 아이콘 이름은 아이콘을 추가할 때 사용하는 이름입니다.

 

 

아이콘 추가하는 방법 1

import { StyleSheet, Text, View } from "react-native";
import AntDesign from 'react-native-vector-icons/AntDesign';

const Headers = () => {
    return (
        <View>
            <Text>Header</Text>
            <AntDesign size={35} name="creditcard" color="#000000" />
        </View>
    );
}


export default Headers;

 

아이콘 추가하는 방법 2

import { StyleSheet, Text, View } from "react-native";
import Icon from 'react-native-vector-icons/FontAwesome';

const myIcon = <Icon name="rocket" size={30} color="red" />;

const Headers = () => {
    return (
        <View>
            <Text>Header</Text>
            {myIcon}
        </View>
    );
}

export default Headers;

 

 

확인해보면 아래처럼 아이콘이 추가된 것을 확인 할 수 있습니다.

 

 

 

React Native... 쉽지 않습니다..

반응형
반응형

React 프로젝트를 진행할 때 ../../../ 와 같은 상대경로가 아닌 @components/, @pages/ 와 같은 절대경로는 설정하는 방법입니다.

프로젝트를 진행할 때 간단한 페이지면 문제가 없는데, redux같은 상태관리를 사용하거나 component가 늘어나면 ../../../component/ 이런식으로 깊어질 때가 있습니다.

이럴때 절대경로를 통해서 최상위부터 시작하는 방법으로 저는 craco를 사용했습니다.

 

Craco

Craco는 Create-React-App Configuration Override의 약자입니다.

CRA를 사용할 때 webpack을 설정하려면 오버라이딩을 해야하는데 이 webpack을 직접 설정하려면 eject를 해야합니다.

하지만 그렇게하게되면 CRA의 장점들이 사라지게 됩니다. ( 트랜스파일링, 번들링 등 )

그래서 이때 Craco 라이브러리를 사용해서 eject를 하지 않고 webpack 설정을 변경해줍니다.

 

npm

$ npm install @craco/craco

 

package.json

  "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "react-scripts eject"
  },

 

scripts부분에 react-scripts부분을 craco로 변경해주었습니다.

 

craco.config.js

const path = require('path');

module.exports = {
  webpack: {
    alias: {
      '@components': path.resolve(__dirname, 'src/components'),
      '@pages': path.resolve(__dirname, 'src/pages'),
      '@styles': path.resolve(__dirname, 'src/styles'),
      '@json': path.resolve(__dirname, 'src/json'),
      '@items': path.resolve(__dirname, 'src/items'),
    },
    "compilerOptions": {
      "baseUrl": "src"
    },
    "include": [
        "src"
    ]
  },
};

 

최상위 경로에 craco.config.js파일을 생성해서 위처럼 오버라이딩 할 설정을 해줍니다.

 

이후 저같은 경우 babel-preset-react-app, is importing the "@babel/plugin-proposal-private-property-in-object" package without declaring it in its dependencies 이런 경고창이 보였습니다.

 

저같은 경우는 stack overflow를 따라 아래처럼 해결했습니다.

stack overflow 바로가기

$ npm install --save-dev @babel/plugin-proposal-private-property-in-object

 

 

반응형
반응형

React Native 프로젝트 생성하고 앱을 실행하는 방법입니다.

xcode와 Android Studio가 설치된 이후에 시작하는 내용입니다.

 

brew install

$ brew install node
$ brew install watchman

 

node version은 18이상으로 설치해줍니다.

watchman은 파일 시스템의 변경 사항을 감시하기 위한 도구입니다.

 

:: watchman 설치 에러가 일어날 때

python@3.11: the bottle needs the Apple Command Line Tools to be installed. You can install them, if desired, with: xcode-select --install

 

위와같은 에러가 나오면 아래 내용을 입력해줍니다.

$ xcode-select --install

 

 

react native cli 생성하기전에 이전에 글로벌로 react-native-cli를 설치한적이 있다면 제거해줍니다.

:: 이전에 글로벌로 설치한 경우 문제가 발생할 수 있다고 합니다.

$ npm uninstall -g react-native-cli @react-native-community/cli

 

 

프로젝트 생성하기

생성할 때, cocoaPods추가 내용이 나왔을 때 y 해주었습니다. ( 종속성 관리 시스템입니다. )

$ npx react-native@latest init AwesomeProject

 

특정 버전으로 새 프로젝트를 시작할 때

$ npx react-native@X.XX.X init AwesomeProject --version X.XX.X

 

프로젝트 실행하기

$ npm start

 

 

위처럼 실행하면 문제없이 바로 실행이 되는줄 알았습니다...

 


 

에뮬레이터 작동안되는 문제..

Could not determine the dependencies of task ':app:compileDebugJavaWithJavac'

> err...

 

 

문제내용

  • JDK 버전
  • Android 환경변수

 

먼저 java 버전을 확인해줍니다.

$ java --version

 

 

첫번째 문제가, 자바 버전이 11이였기에 문제가 일어났었습니다. 그래서 일단 버전을 17로 올려주었습니다.

 

JDK 17버전 설치하기

$ brew install openjdk@17

 

이후 .zshrc 파일에 경로를 추가해주었습니다.

$ export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"

 

터미널에서 추가하기

위처럼 vi로 적용하거나, 아래처럼 입력하면 .zshrc에 추가하고 변경사항을 저장해줍니다.

$ echo 'export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"' >> ~/.zshrc
$ source ~/.zshrc

 

 

두번째 문제는 안드로이드 환경변수가 설정되어 있지 않아서 발생했습니다.

 

먼저 Android SDK Tools(Obsolete)를 체크해주었습니다.

 

Android SDK Tools체크하러 가기

1. Android Studio에서 SDK Manager로 들어갑니다.

 

2. Android SDK -> SDK Tools -> Hide Obsolete Packages 해제 -> Android SDK Tools (Obsolete ) 체크

 

 

ANDROID_HOME 환경변수 추가하기

.zshrc 파일에 아래 내용을 추가합니다.

ANDROID_HOME에 있는 경로는 위 이미지에 Android SDK Location의 경로입니다.

$ export ANDROID_HOME=/Users/junhyeok/Library/Android/sdk
$ export PATH=$PATH:$ANDROID_HOME
$ export PATH=$PATH:$ANDROID_HOME/emulator
$ export PATH=$PATH:$ANDROID_HOME/tools
$ export PATH=$PATH:$ANDROID_HOME/tools/bin
$ export PATH=$PATH:$ANDROID_HOME/platform-toolsexport PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"

 

위 내용들을 실행하고 난 후에 Android와 iOS 에뮬레이터가 문제없이 작동되었습니다.

반응형
반응형

리액트 프로젝트 생성 방법인 Expo와 React-native CLI에 대한 내용입니다.

 

리액트 네이티브프로젝트를 생성하는 두가지 방법

 

Expo와 React Native의 장단점

 

Expo 장점

  • 초기 환경 세팅이 쉬워서 빠르고 간편하게 만들수 있습니다.
  • React Native의 기본 설정이 구성되어 있습니다.
  • 개발하기 어려운 기능들이 탑재되어 있습니다.
  • 네이티브 관련작업들을 Expo가 관리해줍니다.
  • 모바일 앱 관련 개발에 친숙하지 않은 사람들에게 좋은 도구입니다.
  • Apple, Google Store에 배포와 업데이트가 간단합니다.

Expo 단점

  • 숨겨져 있는 네이티브 파일을 변경하기 어렵습니다.
  • Expo에서 지원하지 않는 네이티브 라이브러리는 사용할 수 없습니다.
  • 네이티브 기능을 완벽하게 다룰 수 없기 때문에 한계가 명확합니다.

 

React Native CLI 장점

  • 네이티브로 어플리케이션 개발이 가능합니다.
  • 다양한 라이브러리를 사용할 수 있습니다.
  • 필요한 기능을 직접 만들어서 사용할 수 있습니다.

React Native CLI 장점

  • Android, IOS에 대한 네이티브 지식이 필요합니다. ( 러닝커브가 높습니다. )
  • 초기 환경 세팅이 어렵습니다.
  • 빌드시 Android Studio, Xcode를 이용한 별도의 과정과 장비가 필요합니다.

 

어떤걸 선택해야 하는가 ?

Expo를 사용하게되면 결국 eject를 고민하는 순간이 옵니다.

예를들어 핸드폰 자체 기능을 사용한 기능이 거의 들어가지 않고 JS비중이 높은 간단한 어플이라면 Expo를 사용해도 무방하지만 핸드폰 자체 기능이 하나 둘씩 들어가다보면 결국 한계가 오게됩니다.

또한 이제 빌드를 하게되면 Expo는 무료를 사용하게 되면 빠르면 30분 느리면 1시간 이상 걸리는걸 확인할 수 있습니다.

 

결론은 정말 간단하고 핸드폰 기능이 없는 앱을 만들 경우에는 Expo를 사용하고 그 이외에는 React Native를 사용하는 것이 맞지 않을까라는 생각을 하게 되었습니다.

 

반응형
반응형

React 무한 스크롤 구현하는 방법입니다.

 

npm

$ npm install react-intersection-observer --save
$ npm install sass --save

 

App.tsx

import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Main from "./page/main";
import Scroll from "./page/scroll";
import "./styles/_reset.scss";

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Main />}></Route>
        <Route path="/scroll" element={<Scroll />}></Route>
      </Routes>
    </Router>
  );
}

export default App;

 

scroll.tsx

import { useEffect, useState } from "react";
import "../styles/scroll.scss";
import Card from "../components/scroll/card";
import { DataProps } from "../interface/scroll";
import { useInView } from "react-intersection-observer";

const Scroll = () => {

    // scroll
    const [ref, inView] = useInView();

    // JSON DATA ( FAKE DATA)
    const [data, setData] = useState<DataProps[]>([]);

    const productFetch = () => {
        fetch(`https://jsonplaceholder.typicode.com/posts`)
        .then(response => response.json())
        .then((json: DataProps[]) => {
            setData([...data, ...json])
        })
    }

    useEffect(() => {
        if (inView) productFetch();
        // data 종속성 누락으로 인해 추가한 내용입니다.
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [inView])

    return (
        <section>
            {/* 카드 */}
            <ul>
                {
                    data.length > 0 && data.map((item, index) => (
                        <li key={index}>
                            <Card item={item} />
                        </li>
                    ))
                }
                {/* Render부분에 닿으면 inView가 true가 되면서 새로운 데이터를 불러옵니다. */}
                <li ref={ref}>Render</li>
            </ul>
        </section>
    );
}

export default Scroll;

 

card.tsx

import React from "react";
import { DataProps } from "../../interface/scroll";

interface CardProps {
    item: DataProps
}

const Card: React.FC<CardProps> = ({ item }) => {
    return (
        <div>
            {item.id}
        </div>
    );
}

export default Card;

 


 

Intersection Observer API?

Intersection Observer API는 대상 요소와 상위 요소 또는 최상위 문서의 뷰포트의 교차점에서 변경 사항을 비동기적으로 관찰하는 방법을 제공하는 API입니다.

 

웹 애플리케이션의 무한 스크롤뿐만 아니라 이미지 및 기타 리소스의 지연 로딩을 구현하는 데 자주 사용됩니다.

  • 페이지 스크롤 시 이미지를 Lazy Loading할 때
  • 무한 스크롤을 통해 새로운 컨텐츠를 불러올 때
  • 광고 수익을 계산하기 위해 광고의 가시성을 참고할 때
  • 사용자가 결과를 볼 것인지에 따라 애니메이션 동작 여부를 결정할 때

 

반응형
반응형

Too many re-renders. React limits the number of renders to prevent an infinite loop. 에러에 관한 내용입니다.

React 렌더링 관련 에러입니다.

렌더 과정에서 state를 변화하는 함수가 있을 때, 반복해서 리렌더링을 하게됩니다. setState를 callback으로 렌더링을 트리거하기 때문이라고 합니다.

이 과정에서 무한루프에 빠지게 되면서 에러가 발생한 내용입니다.

코드를 자세히 살펴보니 오타가 문제였습니다..

 

문제였던 내용

onClick에서 setPokeType( setState )했더니 무한루프에 빠졌던 것이었습니다.

onClick={setPokeType(item.type)

 

문제해결

화살표함수를 사용해서 무한루프에서 빠져나왔습니다.

onClick={() => setPokeType(item.type)

 

반응형
반응형

Clean-Up Function에 대한 내용입니다.

React에서 clean-up 함수는 구성 요소가 마운트 해제되거나 다시 렌더링되기 전에 실행되는 코드입니다.

이는 주로 useEffect Hook에서 메모리 누수를 방지하고 리소스가 적절하게 릴리스되는지 확인하기 위해 가격 지우기, 네트워크 요청 취소, 구독 취소 등의 작업을 수행하는데 사용됩니다.

 

예제

import { useEffect, useState } from "react";

const App = () => {

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

    useEffect(() => {
        // mount 될 때 실행됩니다.
        const fetchData = async () => {
            try {
                const res = await fetch("https://api.ex.com/data");

                const result = await res.json();
                setData(result);
            } catch (err) {
                console.log("Fetching Data", err);
            }
        }

        fetchData();

        return () => {
            // unmount 될 때 실행됩니다.
            console.log("clean-up function ~");
        }
    }, [])

    return (
        <section>
            TEST
        </section>
    );
}

export default App;

 

  • useEffect Hook은 구성요소가 마운트 될 때 데이터를 가져오는데 사용됩니다.
  • useEffect에서 반환된 정리 기능은 구성 요소가 마운트 해제될 때 또는 다시 렌더링되기 전에 실행됩니다.
  • 빈 배열은 구성 요소가 마운트 될 때 효과가 한 번만 실행되도록 합니다.

애플리케이션에서 잠재적 메모리 누수를 방지하려면 clean-up 함수에 정리 로직을 포함해야 합니다.

 

 


 

실행 시점 알아보기

useEffect Hook은 컴포넌트가 mount, update, unmount 될 때 실행됩니다.

useEffect Hook의 실행은 컴포넌트의 렌더링과 동시에 일어나는 것이 아닌 렌더링이 끝난 후에 일어납니다.

 

Mount 예제

import { useEffect, useState } from "react";

const App = () => {

    console.log("1");

    useEffect(() => {
        console.log("2");
    }, [])

    console.log("3");
    return (
        <section>
            TEST
        </section>
    );
}

export default App;

 

실행순서는 1 -> 3 -> 2 순서로 실행됩니다.

풀어보자면 컴포넌트의 렌더링이 끝난 후에 useEffect의 2가 실행되는 것을 확인 할 수 있습니다.

 

Update, Unmount 예제

import { useEffect, useState } from "react";

const Test = () => {

    const [btn, setBtn] = useState(0);
    console.log("1");

    useEffect(() => {
        console.log("2");

        return () => {
            console.log("Unmount");
        }
    }, [btn])

    console.log("3");
    
    return (
        <section>
            <button onClick={() => setBtn(prev => prev + 1)}>Click</button>
        </section>
    );
}

export default Test;

 

버튼을 클릭 했을 때, 실행순서는 1 -> 3 -> Unmount -> 2 순서로 실행됩니다.

풀어보자면 1과 3이 먼저 실행되고, 그 다음 unmount가 되면서 clean-up 함수를 실행시켜 Unmount를 실행하고 update가 되면서 2를 실행하게 됩니다.

 

clean-up 함수가 바라보는 값

const [btn, setBtn] = useState(0);

useEffect(() => {
    console.log("2", btn);

    return () => {
        console.log("Unmount", btn);
    }
}, [btn])

return (
    <section>
        <button onClick={() => setBtn(prev => prev + 1)}>Click</button>
    </section>
);

 

:: clean-up 함수는 이전의 값을 바라보고 있기 때문에 이 상태에서 버튼을 클릭하면 아래처럼 실행됩니다.

// 처음 눌렀을 때
Unmount 0
2 1

// 두번째 눌렀을 때
Unmount 1
2 2

 

:: 만약에 useEffect에 의존성 배열을 제거하면 useEffect가 실행되지 않기 때문에 useEffect의 내부는 출력되지 않습니다.

 

중첩 Component 예제

import { useEffect, useState } from "react";

const One = () => {
    useEffect(() => {
        console.log("One");
    }, [])

    return <div>One</div>;
}

const Two = () => {
    useEffect(() => {
        console.log("Two");
    }, [])
}

const Test = () => {

    useEffect(() => {
        console.log("Test");
    }, [])
    return (
        <div>
            Test
            <One />
            <Two />
        </div>
    );
}

export default Test;

 

useEffect를 이런식으로 중첩으로 사용하면 One -> Two -> Test 순서로 실행됩니다.

 

그러면 One 컴포넌트 내부에 Two를 넣어주면 어떻게 실행되는지 예상할 수 있습니다.

내부의 내부로 들어갔기 때문에 Two -> One -> Test 순서로 실행됩니다.

 

중첩 Component에 props로 데이터를 전달 예제

import { useEffect, useState } from "react";

const One = (test) => {
    useEffect(() => {
        console.log("One");

        return () => {
            console.log("CleanUp One")
        }
    }, [test])

    return <div>
        One
        <Two test={test} />
    </div>;
}

const Two = (test) => {
    useEffect(() => {
        console.log("Two");

        return () => {
            console.log("CleanUp Two")
        }
    }, [test])
}

const Test = () => {

    const [test, setTest] = useState(0);

    useEffect(() => {
        console.log("Test");

        return () => {
            console.log("CleanUp Test")
        }
    }, [test])
    return (
        <div>
            <button onClick={() => setTest(1)}>클릭</button>
            Test
            <One test={test} />
        </div>
    );
}

export default Test;

 

버튼을 클릭했을 때 실행순서는 "CleanUp Two" -> "CleanUp One" -> "CleanUp Test" -> "Two" -> "One" -> "Test"순서로 실행이 됩니다.

가장 내부의 자식부터 unmount들이 먼저 발동하고 끝난 이후에, 가장 내부의 자식부터 mount가 발동됩니다.

 

 

반응형
반응형

node-sass관련 오류내용입니다.

Module not found: Error: Can't resolve '/Users/junhyeok/Documents/project/react/node_v18/pokemon/node_modules/sass-loader/dist/cjs.js' in '/Users/junhyeok/Documents/project/react/node_v18/~'

 

오랜만에 리액트 새로운 내용을 만들기 위해 리액트를 생성하고 scss작업을 하기위해 node-sass를 npm에서 받아왔는데 문제가 생겼습니다.

node18버전으로 node-sass를 받아왔는데 에러가 발생했습니다.

npmjs에서 확인해본 결과 node18버전에서는 8.0+이상을 받아야하는데 자동으로 7버전이 다운받아진거였습니다.

그래서 바로 8버전이상으로 새로받은다음 실행을 했는데 오류가 늘어나 버렸습니다.

처음에는 node_modules를 다시 받아야하나 해서 node_modules를 지우고 새로 받았는데도 오류가 줄지 않은 상태였습니다.

알고보니 터미널을 새로 켠 상태에서 설치하고 새로받고를 했던것이 문제였습니다.

터미널의 기본 node버전을 14로 설정을 해놨기에 그에 맞춰 구동하고 있던것이었습니다.

 

그래서 바로 node버전을 18로 맞추고 node-sass또한 8.0+이상으로 받았더니 에러는 모두 사라지고 정상 작동이 되었습니다.

 

어찌보면 참 간단한 문제였는데... 금방 고쳤기에 망정이지 길게 끌었으면 굉장히 허탈 할 뻔한 내용이었습니다.

 

앞으로는 이런 문제에 있어서 주의를 해야겠다는 생각을 하게되는 시간이었습니다..

 

:: 그리고 node-sass가 더이상 새로운 기능을 추가하거나 할 계획이 없다고... 아직도 주간에 190만명이상이 받고 있는데.. 아쉽습니다 dart-sass로 넘어가야 할 때인 듯 합니다.

 

문제해결

node18버전에 맞는 node-sass install

 

반응형
반응형

React의 useEffect와 useLayoutEffect에 대한 내용입니다.

React에서 useEffect와 useLayoutEffect는 기능적인 구성요소에서 부작용을 수행할 수 있는 hooks입니다. 목적은 비슷하지만 실행 시점과 구성요소의 렌더링 차단 여부에 있어서는 다릅니다.

:: ) 부작용 ( Side Effect ): 어딘가에서 무언가를 바꾼다고 생각하면 편합니다. ( 부정적인 의미라고 생각하지 않아도 됩니다 )

 

useEffect

useEffect는 기능적인 구성요소에서 부작용을 처리하기 위해 가장 일반적으로 사용되는 React hooks중 하나입니다. 이는 비차단이며 구성 요소가 렌더링된 후에 실행됩니다.

 

useEffect의 인수

  • 부작용 코드가 포함된 함수입니다.
  • 종속성 배열. 이 경우 useEffect는 하나 이상의 종속성이 변경될 때마다 이 효과를 실행합니다.

 

import { useEffect } from "react";

function App() {
    useEffect(() => {
        // Side Effect
        console.log("UseEffect");
    }, [dependency1, dependency2])
    
    return <div>Component</div>;
};

export default App;

 

useEffect의 주요 사항은 아래와 같습니다.

  • useEffect는 비차단( non-blocking )입니다. 즉, 구성 요소의 렌더링을 방해하지 않습니다.
  • 일반적으로 데이터 가져오기, DOM 업데이트 또는 기타 비동기 작업에 사용됩니다.
  • 종속성 배열은 효과가 실행될 때를 제어하는데 필수적입니다. 배열이 비어있으면 초기 렌더링 후에만 실행됩니다. 종속성이 지정되면 그 중 하나가 변경되면 실행됩니다.

 

useLayoutEffect

useLayoutEffect는 부작용을 처리하기 위한 또다른 반응 hooks지만, DOM이 업데이트된 후 브라우저가 화면을 그리기 전에 동기적으로 실행됩니다. 이렇게하면 다음 프레임이 렌더링되기 전에 DOM에서 레이아웃이나 스타일 정보를 읽어야 하는 작업에 적합합니다.

useLayoutEffect는 useEffect와 동일한 두 개의 인수를 사용합니다.

import { useLayoutEffect } from "react";

function App() {
    useLayoutEffect(() => {
        // Synchronous Side Effect
        console.log("UseLayoutEffect");
    }, [dependency1, dependency2])
    
    return <div>Component</div>;
};

export default App;

 

useLayoutEffect의 주요 사항은 아래와 같습니다.

  • useEffect와 비슷하지만 DOM 업데이트 후에 화면이 다시 그려지기 전에 동기적으로 실행됩니다.
  • DOM요소를 측정하거나 레이아웃 및 스타일에 영향을 미치는 DOM 변형을 수행하는 등의 작업에 사용할 수 있습니다.
  • useLayoutEffect는 보다 즉각적인 피드백을 제공하지만 브라우저 렌더링을 차단할 수 있어 신중하게 사용하지 않으면 잠재적으로 성능 문제가 발생할 수 있습니다.

 

useEffect와 useLayoutEffect중 하나를 선택하는 것은 특정 사용 사례에 따라 달라집니다.

  • useEffect: 대부분의 부작용, 특히 비동기식이고 동기식 업데이트가 필요하지 않은 경우에 사용합니다.
  • useLayoutEffect: 레이아웃 정보를 읽거란 즉각적인 스타일 변경 사항을 적용하는 등 DOM과 동기적으로 상호 작용해야 할 때 사용합니다. 그러나 성능에 영향을 줄 수 있으므로 사용할 때는 주의해야 합니다.

 

일반적으로 기능 구성 요소에서 대부분의 부작용에 대해 useEffect를 사용하고, 동기식 레이아웃 관련 작업이 필요한 경우에 useLayoutEffect를 사용합니다.

반응형

+ Recent posts