[3] React.js 주요 개념 이해하기

Doozuu·2023년 4월 10일

React

목록 보기
15/30

📌 이벤트 사용하기

⭐️ react에서는 html과 달리 이벤트에 camelCase를 사용한다.

html에서는 onclick 이라고 나타냈지만 react에서는 onClick 이라고 쓴다.

1. onClick

onClick 이벤트는 특정 element가 클릭됐을 때 정의된 함수를 호출하는 방식으로 사용한다.

2. onChange

onChange 이벤트는 특정 element에 변화가 생겼을 때 정의된 함수를 호출하는 방식으로 사용한다.

3. mouse 이벤트

  • onMouseMove 이벤트는 특정 tag 영역 안에서 마우스 커서가 움직일 때 발생한다.
  • onMouseOver 이벤트는 특정 tag 영역 안에 마우스 커서가 진입할 때 발생한다.
  • onMouseOut 이벤트는 특정 tag 영역 안에 마우스 커서가 진입했다가 벗어날 때 발생한다.

4. key 이벤트

  • onKeyDown 이벤트는 키를 눌렀을 때 동작한다.
    - 키를 누르고 떼는 동작 자체에 반응한다.
  • onKeyPress 이벤트는 키를 눌렀을 때 동작한다.
    - 문자가 실제로 입력됐을 때 반응한다.
  • onKeyUp 이벤트는 눌려 있던 키에서 손을 뗐을 때 동작한다.
    - 키를 누르고 떼는 동작 자체에 반응한다.

5. onSubmit

onSubmit 이벤트는 <form> 태그에 사용한다. <input> 태그를 클릭하거나 enter를 누르면 발생한다.



📌 Ref 사용하기

Ref는 컴포넌트 내부의 요소에 접근할 때 사용된다. Ref를 사용하면 DOM 요소를 직접 조작하거나, 컴포넌트 인스턴스에 접근할 수 있다.

useRef

useRef는 React에서 Ref 객체를 생성하는 Hook이다.
useRef를 사용하면 클래스 컴포넌트의 this.refs와 같은 기능을 함수형 컴포넌트에서 사용할 수 있다.

const myRef = useRef(initialValue);
import React, { useRef } from 'react'; // import 하기

function MyComponent() {
  const inputRef = useRef(null); // input 참조

  const handleClick = () => {
    inputRef.current.focus(); // 버튼 클릭시 focus 효과
  }

  return (
    <div>
      <input type="text" ref={inputRef} /> // 참조할 요소
      <button onClick={handleClick}>포커스</button>
    </div>
  );
}



📌 커링 함수 구현하기

커링(Currying) 함수는 함수를 반환하는 함수로, 여러 개의 인수를 받는 함수를 하나의 인수만 받는 함수들의 중첩 함수로 나누는 것이다.
이를 통해 함수의 재사용성을 높일 수 있다.

function multiply(x) {
  return function(y) {
    return x * y;
  }
}

// 위 함수를 ES6 화살표 함수로 간단히 표현하면 다음과 같다.
const multiply = x => y => x * y;

const double = multiply(2); // (y) => 2 * y
const triple = multiply(3); // (y) => 3 * y

console.log(double(4)); // 8
console.log(triple(4)); // 12



📌 고차 컴포넌트 구현하기

커링과 같이 함수 자체를 인자로 받거나 반환하는 함수를 고차 함수라고 한다.
이와 비슷하게 컴포넌트를 인자로 받거나 반환하는 함수를 고차 컴포넌트라고 한다.

  1. MyComponentWithLoadingIndicator는 withLoadingIndicator함수를 실행시킨다.
  2. withLoadingIndicator함수는 props에서 isLodaing과 나머지 데이터를 분리해 isLoading이 true일 때 로딩 문구를 return하고, 그 외에는 Component에 나머지 데이터를 전달한다.
  3. Component는 나머지 데이터를 props로 받아서 데이터의 title과 content를 보여준다.
import React from 'react';

function withLoadingIndicator(Component) {
  return function WithLoadingIndicator(props) {
    const { isLoading, ...rest } = props;

    if (isLoading) {
      return <div>Loading...</div>;
    }

    return <Component {...rest} />;
  }
}

function MyComponent(props) {
  const { data } = props;

  return (
    <div>
      <h1>{data.title}</h1>
      <p>{data.content}</p>
    </div>
  );
}

const MyComponentWithLoadingIndicator = withLoadingIndicator(MyComponent);

function App() {
  const isLoading = true;
  const data = { title: 'Hello', content: 'World!' };

  return (
    <MyComponentWithLoadingIndicator isLoading={isLoading} data={data} />
  );
}



📌 Context api 사용하기

props를 사용하면 데이터를 부모 컴포넌트에서 자식 컴포넌트로 전송할 수 있다.

그런데 만약 손자 컴포넌트가 부모 컴포넌트의 데이터를 필요로 한다면, 자식 컴포넌트가 중간에서 데이터를 전달해야 한다.(부모 -> 자식 -> 손자로 전달)

이때 자식 컴포넌트가 부모 컴포넌트의 데이터가 필요하지 않은 상황이라면 불필요한 코드를 작성하게 된다.(관계가 깊어질수록 전달하기가 매우 번거로워진다.)

컨텍스트는 데이터의 공급자와 소비자를 정의하고 데이터가 필요한 컴포넌트만 사용할 수 있게 구현할 수 있다.

useContext

일반적으로 컨텍스트는 여러 컴포넌트에서 공유해야 하는 데이터를 저장하고, 이를 자식 컴포넌트에서 사용할 수 있도록 한다. 컨텍스트는 전역으로 사용할 수 있어야 하기 때문에, 보통 최상위 컴포넌트에 위치한다.

예제

ThemeContext.js

import {createContext, useState} from 'react'; // createContext import하기

const themes = {
  light: {
    foreground: '#000000',
    background: '#eeeeee'
  },
  dark: {
    foreground: '#ffffff',
    background: '#222222'
  }
};
// ThemeContext 객체를 만들어 초기값으로 themes.light 전달
export const ThemeContext = createContext(themes.light); 

// ThemeProvider 생성
export const ThemeProvider = ({children}) => {
  const [theme,setTheme] = useState(themes.light);
  
  return(
     <ThemeContext.Provider value={theme}>
    	{children}
    </ThemeContext.Provider>
  )
}
  1. createContext를 이용해 컨텍스트를 만든다.
  2. 컨텍스트의 provider를 만든다.
    • ThemeContext 객체를 사용하려면 ThemeContext.Provider 컴포넌트를 사용해야 한다. ThemeContext.Provider 컴포넌트의 value prop에는 ThemeContext 객체에서 사용할 값을 지정할 수 있다.
    • 또한, 자식 컴포넌트들을 ThemeProvider 컴포넌트로 감싸면 하위 컴포넌트에서 ThemeContext를 사용하여 theme 값을 참조할 수 있다.

ChildComponent.js

import {useContext} from 'react'; // useContext import하기
import {ThemeContext} from '../ThemeContext'; // 사용할 컨텍스트 import 하기

function ChildComponent() {
  const theme = useContext(ThemeContext); // useContext를 이용해 컨텍스트에서 데이터 가져오기

  return (
    <div style={{ color: theme.foreground, backgroundColor: theme.background }}>
      This is a child component
    </div>
  );
}

export default ChildComponent;
  1. 컨텍스트를 사용할 컴포넌트에서 useContext와 사용할 컨텍스트를 import 해온다.
  2. useContext를 이용해 컨텍스트에서 데이터를 가져와 사용한다.
    • ThemeContext.Provider 컴포넌트를 사용하지 않고, useContext Hook을 사용하면, 초기값이 undefined로 설정되어 에러가 발생할 수 있다.

📌 Context로 부모 데이터 변경하기

props는 데이터가 부모에서 자식 컴포넌트로 단방향으로만 이동할 수 있다. 하지만 컨텍스트를 사용하면 자식 컴포넌트에서 부모 컴포넌트의 데이터를 변경할 수 있다.

-> Provider 컴포넌트에서 상태를 변경하는 함수를 작성하고 이를 value로 전달하면, 자식 컴포넌트에서 전달받은 함수를 이용해 부모 데이터를 변경할 수 있다.

부모 컴포넌트

import { createContext, useState } from 'react';

const MyContext = createContext();

const ParentComponent = () => {
  const [state, setState] = useState({
    name: 'John',
    age: 30,
  });

  const updateState = (name, age) => {
    setState({
      ...state,
      name,
      age
    });
  };

  return (
    <MyContext.Provider value={{ state, updateState }}>
      <ChildComponent />
    </MyContext.Provider>
  );
};

export default ParentComponent;

업데이트 함수의 setState안에 ...state를 쓰는 이유

  • setState 함수를 사용하여 상태를 업데이트할 때, 이전 상태를 완전히 덮어쓰는 대신, 기존 상태의 일부를 변경하고자 할 때 사용된다.
  • ...state는 객체 분해 할당을 사용하여, state 객체의 모든 속성을 현재 상태로 복사하고 새로운 값을 할당하여 변경된 상태를 만든다.
  • 위 코드에서는 기존 state 객체의 모든 속성을 ...state로 복사한 후, name과 age만 새로운 값으로 업데이트하여 새로운 객체를 생성한다.
  • 이렇게 하면 기존 상태를 완전히 덮어쓰지 않고, 일부 속성만 변경할 수 있기 때문에 효율적인 상태 업데이트가 가능하다.

자식 컴포넌트

import { useContext } from 'react';
import MyContext from './MyContext';

const ChildComponent = () => {
  const { state, updateState } = useContext(MyContext);

  const handleClick = () => {
    updateState('Jane', 25); 
    // 컨텍스트로부터 전달받은 update함수를 이용해 부모 데이터 갱신
  };

  return (
    <div>
      <p>{state.name}</p>
      <p>{state.age}</p>
      <button onClick={handleClick}>Update State</button>
    </div>
  );
};

export default ChildComponent;
// 버튼을 클릭하면 'John', 30 에서 'Jane', 25로 바뀐다.



📌 Redux - reducer로 스토어 생성하기

redux는 컨텍스트와 마찬가지로 데이터를 필요한 컴포넌트에서만 요청해 사용할 수 있다.

  • 컨텍스트는 부모 컴포넌트에서 생성한 데이터에 모든 자식 컴포넌트에서 접근할 수 있다.
  • 하지만 redux에서는 컴포넌트 외부의 스토어라는 곳에서 관리한다.
    그래서 컴포넌트 위치에 상관없이 스토어에 접근해 데이터를 사용하고 변경할 수 있다.

redux 설치

npm install --save redux

redux는 데이터를 스토어 > 컴포넌트 > 액션 > 리듀셔 > 다시 스토어의 과정을 통해 변경한다.

index.js

import {createStore} from 'redux'; // 스토어 생성 함수
import reducers from './reducers'; // 데이터 초깃값 설정하고 데이터 변경해주는 함수

const store = createStore(reducers); // store 생성

const listener = () => {
	ReactDOM.render(
    	<App store={store}/>,
        document.getElementById('root')
    );
};

store.subscribe(listener); 
// store를 구독하면 store 데이터에 변화가 있을 때 listener 내부의 render 함수를 실행하고 변경된 데이터를 렌더링한다.
listener(); // 초기 렌더링을 위해 수동으로 render 함수 실행

redux 파트 79 ~ 84는 나중에 추가.



📌 react-cookies save 사용하기

쿠키란 사용자가 접속한 웹 사이트의 서버를 통해 사용자 컴퓨터에 설치되는 정보를 말한다.
쿠키는 사용자 정보를 저장하거나 마케팅을 위한 목적으로 사용될 수 있다.

설치

npm install react-cookies --save

예제

save 함수의 세 가지 파라미터 : 쿠키의 키(userid), 쿠키 값(Doozuu), 쿠키 옵션

import React from "react";
import { Component } from "react";
import cookie from 'react-cookies'; // import

class R085_cookieSave extends Component {
    componentDidMount() {
        const expires = new Date()
        expires.setMinutes(expires.getMinutes() + 60)  // 현재 시간으로부터 60분 후 만료
        cookie.save('userid' , "Doozuu" ,{
            path : '/',   // 쿠키값을 저장하는 서버 경로
            expires,  // 쿠키의 유효시간
            // secure : true // https인 경우에만 쿠키 저장
            // httpOnly : true  // document.cookie로 쿠키 접근하는 것 방지
        });
    }

    render () {
        return (
            <><h3>react-cookies Save</h3></>
        )
    }
}

export default R085_cookieSave;



📌 react-cookies load 사용하기

save 함수가 쿠키를 key-value 쌍으로 저장하는 함수였다면, load 함수는 웹 브라우저에 남아 있는 쿠키에 key로 접근해 value를 가져오는 함수다.

예제

cookie.load(key) : key에 해당하는 value를 가져온다.
쿠키가 저장되기까지 충분한 시간을 두기 위해 setTimout을 사용한다.

import React from "react";
import { Component } from "react";
import cookie from 'react-cookies'; // import

class R085_cookieSave extends Component {
    componentDidMount() {
        const expires = new Date()
        expires.setMinutes(expires.getMinutes() + 60)  // 현재 시간으로부터 60분 후 만료
        cookie.save('userid' , "Doozuu" ,{
            path : '/',   // 쿠키값을 저장하는 서버 경로
            expires,  // 쿠키의 유효시간
            // secure : true // https인 경우에만 쿠키 저장
            // httpOnly : true  // document.cookie로 쿠키 접근하는 것 방지
        });
      setTimeout(function(){
        alert(cookie.load('userid')) // 1초 후 Doozuu 출력
      },1000);
    }

    render () {
        return (
            <><h3>react-cookies Save</h3></>
        )
    }
}

export default R085_cookieSave;



📌 react-cookies remove 사용하기

remove 함수는 웹 브라우저에 남아 있는 쿠키에 key로 접근해 쿠키를 삭제하는 함수다.

예제

import React from "react";
import { Component } from "react";
import cookie from 'react-cookies'; // import

class R085_cookieSave extends Component {
    componentDidMount() {
        const expires = new Date()
        expires.setMinutes(expires.getMinutes() + 60)  // 현재 시간으로부터 60분 후 만료
        cookie.save('userid' , "Doozuu" ,{
            path : '/',   // 쿠키값을 저장하는 서버 경로
            expires,  // 쿠키의 유효시간
            // secure : true // https인 경우에만 쿠키 저장
            // httpOnly : true  // document.cookie로 쿠키 접근하는 것 방지
        });
      setTimeout(function(){
        cookie.remove('userid', { path: '/'}); // 1초 후 useid의 쿠키 값 삭제
      }, 1000); 
      setTimeout(function(){
        alert(cookie.load('userid')) // 1초 후 Doozuu 출력
      },1000);
    }

    render () {
        return (
            <><h3>react-cookies Save</h3></>
        )
    }
}

export default R085_cookieSave;



📌 react-router-dom BrowerRouter 사용하기

라우팅이란, 호출되는 url에 따라 페이지 이동을 설정하는 것이다.
라우팅을 지원하는 패키지로 react-router-dom이 있다.

react-router-dom 패키지는 BrowerRouter, Router, Link의 기능을 제공한다.

  • Router는 호출되는 url에 따라 이동할 component를 정의한다.
  • Link는 a 태그와 같이 페이지에 표시되는 링크를 클릭하면 url을 호출한다.
  • Router와 Link를 사용하기 위해서는 BrowerRouter 태그로 감싸 사용해야 한다.
    (index.js 에서 <App/> 을 BrowerRouter 태그로 감싸준다.)

설치

npm install --save react-router-dom



📌 react-router-dom Route 사용하기

  1. Route를 import한다.
  2. Route 태그에 path 속성으로 호출되는 url 경로, component 속성으로 연결할 컴포넌트를 할당한다.

App.js

import React, {Component} from 'react';
import reactRouter from './reactRouter';
import reactRouter2 from './reactRouter2';
import {Route} from 'react-router-dom'; // import 

class App extends Component{
  	render(){
      return(
        <div className="App">
            <Route exact path='/' component={reactRouter} />
            <Route exact path='/reactRouter2' component={reactRouter2} />
        </div>
		);
    }
}

export default App;



Link는 a 태그와 동일하게 동작한다.

  1. Link를 import 한다.
  2. to 속성으로 이동할 경로를 입력한다.

예시

<Link to={'/reactRouter2'}>reactRouter2</Link>



📌 <react img> 태그 사용하기

react에서는 require 문법을 사용해 이미지 경로를 할당해야 한다.

예시

<img src={require("../img/main/log_img.png") alt=""}/>



📌 lodash 디바운스 사용하기

debounce는 연속된 이벤트 호출이 일어나는 상황에 사용한다.

  • 마지막 이벤트가 실행되고 일정 시간 동안, 추가 이벤트가 발생하지 않을 때 실행되는 함수다.
  • debounce는 꼭 필요한 시점에만 함수를 실행해 서버 자원을 효율적으로 사용할 수 있게 해준다.

설치

npm install --save lodash

예제

  1. 텍스트가 입력될 때마다 debounce 함수를 호출한다.
  2. debounce 함수에 1초의 지연 시간을 할당한다.
  • 실제로 사용자가 입력한 텍스트가 포함된 검색어를 불러와야 할 때, 디바운스를 사용하지 않고 react라는 글자를 입력한다면 r,re,rea,reac,react가 입력되는 시점에 모두 데이터를 호출해야 한다.
  • 그러나 디바운스를 사용하면 react라는 글자가 모두 작성되고 지연 시간 1초가 지난 후 데이터를 한 번만 호출한다.
import React, { Component } from 'react';
import { debounce } from 'lodash'; // import

class reactDebounce extends Component {
	debounceFunc = debounce( () => {
    	console.log("Debounce API Call");
        }, 1000);
    
    render() {
    	return (
        	<>
            	<h2> 검색어 입력 </h2>
                <input type="text" onChange={this.debounceFunc} />
            </>
        )
    }
}

export default reactDebounce;



📌 lodash 스로틀 사용하기

throttle도 debounce와 동일하게 시간 조건을 추가해 실행 횟수를 제한한다.
차이점은 debounce가 연속된 이벤트 중 마지막 이벤트가 발생한 시점부터 특정 시간이 지났을 때 동작한다면, throttle은 발생한 이벤트 수와 관계없이 지정한 시간 단위당 최대 한 번만 동작한다는 것이다.

  • 1초의 실행 시간 간격을 할당한다면, throttle 함수는 1초마다 0개 또는 1개의 로그를 출력한다.

  • 만약 react 라는 검색어를 0초(r), 0.3초(e), 0.5초(a), 1.1초(c), 2초(t)에 입력했다면, throttle은 0초(r), 1초(rea), 2초(react)에 1초 단위로 데이터 호출 코드를 실행한다.

profile
모든게 새롭고 재밌는 프론트엔드 새싹

0개의 댓글