반응형

useRef를 사용해서 스크롤을 이동시키는 방법입니다.

 

App.js

import { useRef } from "react";

const App = () => {

    const scrollRef = useRef(null);

    const move = () => {
        scrollRef.current.scrollIntoView({ behavior: 'smooth' });
    };

    return (
        <>
            <div ref={scrollRef}>여기로 이동합니다.</div>
            
            <button onClick={move}>버튼을 누르면</button>
        </>
    );
};


export default App;

- ScrollIntoView

특정 엘리먼트 위치로 스크롤을 이동시켜주는 내장메서드입니다. 인자로 true / false, option을 받을 수 있습니다.

option으로 block, inline, behavior이 있습니다.

block : start / end [ 수직 요소에 대한 옵션 ]

inline : start / left / center / nearest [ 수평 요소에 대한 옵션 ]

behavior : auto / smooth [ 스크롤시 움직임에 대한 옵션 ]

반응형
반응형

useEffect, useMemo, useCallback에 대하여

 

useEffect()

- 시작할 때 한번 실행시키거나, 어떤 요소가 업데이트되면 그에 따라 실행시켜줍니다.

 

// 기본
useEffect(() => {}, []);

{} 동작하는 부분, [] 내부 요소가 업데이트되면 작동

 

사용방법

import { useEffect, useState } from "react";

const App = () => {
    const [test, setTest] = useState(false);
    
    useEffect(() => {
        if (test === true) {
            console.log('test가 true일때만 실행됩니다. 이후 test는 다시 false로 초기화 시켜줍니다.');
            setTest(false);
        }
    }, [test]);
};

export default App;

위 코드는 test 변수가 업데이트 될때마다 useEffect에 전달한 함수가 실행됩니다. 

 

 

useCallback()

- 내가 원하는 타이밍에 실행시킬 수 있는 함수를 만들기 위해 사용합니다.

 

사용방법

import { useCallback, useEffect, useState } from "react";

const App = () => {
    const [test, setTest] = useState(false);
    const [inputValue, setInputValue] = useState('');
    
    useEffect(() => {
        if (test === true) {
            inputAdd();
            setTest(false);
        }
    }, [test, inputAdd]);

    const inputAdd = useCallback(() => {
        console.log(`inputValue가 업데이트 될때마다 실행되지 않고 test가 true가 될때만 실행시키고 싶습니다.${inputValue}`)
    }, [inputValue]);
};

export default App;

위 코드는 inputValue 내용을 test가 true가 될때마다 useEffect의 inputAdd()함수가 호출됩니다.

inputValue(내가 원하지 않는 타이밍)가 업데이트 될때가 아닌 test(내가 원하는 타이밍)일 때 함수를 실행시킬 수 있습니다.

 

 

useMemo()

- 원하는 값을 업데이트하기 위해 사용됩니다.

:: useMemo는 값을 반환해줍니다. useMemo는 []가 변하면 {}내부를 실행시키고, 그 함수의 반환 값을 반환해줍니다.

 

사용방법

import { useMemo, useState } from "react";

const App = () => {

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

    useMemo(() => {
        console.log('실행', test)
    }, [test]);

    return (
        <>
            <button onClick={() => setTest((current) => (current + 1))}>Update</button>
            <button onClick={() => setTest2((current) => (current + 1))}>Update2</button>
        </>
    );
};


export default App;

위 코드는 [test]가 변할 때만 내부 console.log()를 실행합니다. 그렇기 때문에 Update2버튼을 눌러서 App 컴포넌트 함수를 전부 재실행시켜도 test가 변화하지 않았기 때문에 useMemo에 변화는 생기지 않습니다.

 

 


useCallback과 useMemo

useMemo는 memoization된 '값'을 반환하고, useCallback은 memoization된 '함수'를 반환합니다.

:: memoization : 기존 연산의 결과 값을 메모리 어딘가에 저장하고, 동일한 입력이 들어왔을 경우 재활용하는 프로그래밍 기법입니다. memoization를 많이 사용하면 메모리를 많이 잡아먹게 되지만, 적절히 사용하면 중복 연산을 피할 수 있기에 성능을 최적화 시킬 수 있습니다.

 

목적

useMemo : 함수의 연산량이 많을 때, 이전 결과 값을 재사용할 때

useCallback : 함수가 재생성 되는것을 방지할 때

 

반응형
반응형

React Hook useEffect has a missing dependency: '변수명'. Either include it or remove the dependency array  react-hooks/exhaustive-deps

Search for the keywords to learn more about each warning. To ignore, add // eslint-disable-next-line to the line before.

 

Test.js ( 전체코드가 아닌 일부 코드만 가져왔습니다. )

태그를 추가하고 같은 태그가 있을 경우에는 추가하지 않는 코드입니다.

import { useEffect, useState } from "react";


const Test = () => {
    const [tags, setTags] = useState([]);
    const [tag, setTag] = useState('');

    useEffect(() => {

        let confirm = false;

        for (let i = 0; i < tags.length - 1; i++) {
            if (tags[i] === tag) confirm = true;

            if (tags.length - 1 === i + 1) {
                if (confirm === true) {
                    let newTagArray = tags.slice(0, -1);

                    setTags([...newTagArray]);
                }
            }
        }

        setTag('')
    }, [tag, tags])
};

export default Test;

useEffect에 [] 부분에 종속된 내용들을 추가해 주어야 하는 상황이 생겼습니다.

그래서 [] 부분에 tag, tags를 추가해서 넣어서 실행했을때 문제없이 작동은 했지만, 실제로 실행하는 부분에서 글자를 입력할때마다 실행되는 문제가 생겼습니다.

이후 원하는 타이밍에 호출시키기 위해 useCallback을 사용했습니다.

 

Test.js ( 전체코드가 아닌 일부 코드만 가져왔습니다. )

import { useCallback, useEffect, useState } from "react";


const Test = () => {
    const [tags, setTags] = useState([]);
    const [tag, setTag] = useState('');
    const [tagBoolean, setTagBoolean] = useState(false);

    useEffect(() => {
        if (tagBoolean === true) {
            tagTest();
            setTagBoolean(false);
        }
    }, [tagTest, tagBoolean])

    const tagTest = useCallback(() => {
        let confirm = false;

        for (let i = 0; i < tags.length - 1; i++) {
            if (tags[i] === tag) confirm = true;

            if (tags.length - 1 === i + 1) {
                if (confirm === true) {
                    let newTagArray = tags.slice(0, -1);

                    setTags([...newTagArray]);
                }
            }
        }

        setTag('')
    }, [tag, tags]);
};

export default Test;

어떤 특정한 행동을 했을 때 tagBoolean을 true로 바꿔서 tagTest부분을 실행하도록 해주었습니다.

그리고 특정행동을 마치고 난 뒤에는 다시 tagBoolean을 false로 바꿔주었습니다.

 

 

반응형
반응형

dotenv 바로가기

 

npm

$ npm install dotenv

 

.env ( 최상위 폴더에 생성합니다. )

REACT_APP_PORT = 4000

React에서 .env를 작성할 때는 REACT_APP_을 붙여준 뒤에 이름을 정해줍니다.

 

app.js

const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);

require("dotenv").config();

const PORT = process.env.REACT_APP_PORT || 4001;

server.listen(PORT, () => {
    const message = `
        [ App Project ]
        Running PORT: localhost:${PORT}
    `;

    console.log(message);
});

.env 내용을 불러올때는 process.env.을 붙여준 뒤에 .env내용을 불러옵니다.

 

 

반응형
반응형

npm

$ npm install react-router-dom

App.js

 

import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

import Main from './components/main/Main';
import Article from './components/article/Article';

const App = () => {
    return (
        <Router>
            <Routes>
                <Route path="/" element={<Main />} />
                <Route path="/article/:id" element={<Article />} />
            </Routes>
        </Router>
    );
};

export default App;

 

Main.js

import { useNavigate } from 'react-router-dom';

const Main = () => {

    const navigation = useNavigate();

    const move = () => {
        navigation('/article/abc');
    };
    
    return (
        <div>
            <button onChange={move}>이동</button>
        </div>
    );
};

export default Main;

 

Article.js

import { useLocation, useParams } from 'react-router-dom';

const Article = () => {

    const location = useLocation();
    const params = useParams();
    
    console.log(location); // hash, key, pathname, search, state
    console.log(params); // {id: 'abc'}
    
    return (
        <div>article</div>
    );
};

export default Article;

 

useLocation으로 받을때는 전체 주소를 받을 수 있습니다.

:: ) useNavigate()에 state를 추가해서 보낼수도 있습니다.

useParams로 받을때는 변수부분(:id)만 따로 받을 수 있습니다.

반응형
반응형

삼항연사자를 이용해서 style값 변경하기

import { useState } from 'react';

const App = () => {
    const [test, setTest] = useState('');
    
    const onChange = (option) => {
        if (option === '1') setTest('1');
        else setTest('2');
    };
    
    return (
        <div>
            <div onClick={() => onChange('1')} style={{background: test === '1' ? 'blue' : ''}}>test1</div>
            <div onClick={() => onChange('2')} style={{background: test === '2' ? 'orange' : ''}}>test2</div>
        </div>
    );
}

export default App;

 

삼항연사자를 이용해서 className값 변경하기

import { useState } from 'react';

const App = () => {
    const [test, setTest] = useState('');
    
    const onChange = (option) => {
        if (option === '1') setTest('1');
        else setTest('2');
    };
    
    return (
        <div>
            <div onClick={() => onChange('1')} className={test === '1' ? 'adc' : ''}}>test1</div>
            <div onClick={() => onChange('2')} className={test === '2' ? 'def' : ''}}>test2</div>
        </div>
    );
}

export default App;

 

반응형
반응형

내장함수 .map()을 사용해서 컴포넌트를 반복적으로 생성하는 방법입니다.

 

App.js

const App = () => {
    
    const arrayData = [
        {
            id: 0,
            title: '제목1'
        },
        {
            id: 1,
            title: '제목2'
        },
        {
            id: 2,
            title: '제목3'
        },
    ];
    retrun (
        {
            arrayData.length > 0 ? (
                arrayData.map((item) => (
                    <div key={item.id}>
                        {item.title}
                    </div>
                ))
            ) : null
        }
    );
}

export default App;

arrayData.length > 0 ? () : null : 삼항연산자 => arrayData내용이 있는 경우에만 ()안에 내용을 보여주고 아닐 경우에는 아무것도 보여주지 않습니다. 

key : 키값은 고유키값을 포함시켜 주어야 합니다. 포함시키지 않을 경우에는 react가 오류를 발생시킵니다.

 

:: ) 주의 : map()을 사용할 때, 항상 (), {}를 잘 구분해야 합니다. 습관적으로 () => {}를 사용하는 사람들은 에러가 나는 경우가 종종 생깁니다.

반응형
반응형

React에서 axios를 모듈화 시키는 방법입니다.

 

axios를 모듈화 시키는 이유

아래는 axios를 일반적으로 만드는 여러가지 방법중 하나입니다.

 

App.js

import axios from 'axios';
import { useEffect } from 'react';

const App = () => {

    const serverUrl = 'http://localhost:4000/api/find';
    
    useEffect(() => {
        axios.get(serverUrl)
        .then(res => {
            
        })
        .catch(err => console.log(err));
    }, [])
}

export default App;

위와 같이 사용할 경우 serverUrl를 계속해서 가지고 다녀야 하는 상황이 생깁니다. 이럴때 모듈화를해서 사용하면 자동으로 값을 넣어줄 수 있습니다.

 

axios를 모듈화 시키기

 

api.js

import axios from "axios";

const api = axios.create({
    baseURL: "http://localhost:4000/api",
    headers: {}
});

export { api };

App.js

import axios from 'axios';
import { useEffect } from 'react';

const App = () => {
    
    useEffect(() => {
        axios.get('/find')
        .then(res => {
            
        })
        .catch(err => console.log(err));
    }, [])
}

export default App;

모듈화를 시켰을때 장점은 serverUrl을 따로 써줄 필요성이 사라졌고, headers( ex: 사용자 토큰 )를 태워서 보내줄 수 있습니다.

 

반응형
반응형

className 두 개 이상 적용시키는 방법입니다.

 

default.css [ css module이 아닌 경우 ]

import 'default.css';

const App = () => {
    return (
        <div className="add1 add2"></div>
    );
}

export default App;

 

default.module.css [ css module인 경우 ]

import style from 'default.module.css';

const App = () => {
    return (
        <div className={`${style.add1} ${style.add2}`}></div>
        <div className={[style.add1, style.add2].join(" ")}></div>
    );
}

export default App;

두 가지 중 편한 방법으로 사용하면 될 것 같습니다.

반응형
반응형

react-router-dom v6 바로가기

 

npm ( ver.6 )

$ npm install react-router-dom

 

App.js

import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Main from './components/Main';

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

export default App;
<Link to="/">Router 이동</Link>
  • BrowserRouter : react-router-dom의 라우터는 BrowserRouter와 HashRouter 두가지가 있습니다.
    BrowserRouter는 HTML5의 history API를 활용하여 UI를 업데이트하고, HashRouter는 URL의 hash를 활용한 라우터입니다.
    :: ) HashRouter는 정적인( Static )페이지에 적합합니다. 대부분 request & response로 이루어진 동적인( Dynamic )페이지를 제작하기 때문에 BrowserRouter를 사용합니다.
  • Routes : 자식 컴포넌트 Route또는 Redirect중 매치되는 첫 번째 요소를 렌더링해줍니다. 만약 Routes를 사용하지 않고, BrowserRouter만 사용할 경우에는 하나의 요소만 렌더링하지 않고, 모두 출력하게 됩니다. 이전 v5에서는 Switch였으며 이름만 바뀌었다고 생각하면 됩니다.
  • Route : 컴포넌트의 속성에 설정된 path주소와 주소창에 경로가 일치하면 해당 컴포넌트, 함수를 렌더링합니다. v5에서는 element={<Component />}대신 component={() => <Component />}를 사용했었습니다.
  • * Link : Link는 a태그와 같습니다. to속성에 설정된 링크로 이동시켜줍니다. 기록은 history스택에 저장됩니다.

 

반응형

+ Recent posts