220508 TIL

klucas·2022년 5월 8일
0

TIL DAY 181

오늘 배운 일

✔️ 리액트 복습!

유튜브 별코딩님의 강의를 보고 따라만든 나의 리액트 프로젝트

🔊 useRef

우리가 자바스크립트에서는 DOM에다가 접근할려면...

document.querySelector('input') <- 이러한 형태로 만들어야했다.

하지만, 리액트는 간편하게 Hook 중 하나인 useRef 를 사용한다!

기본적인 형태

 const inputRef = useRef()

위의 코드를 보면, useRef 괄호 안에는 초기값을 넣어준다.

그러면 이제 기본적인 예를 들어보겠다.

App.js

import { useEffect, useRef } from "react";
import "./styles.css";

export default function App() {
  const inputRef = useRef();

  useEffect(() => {
    inputRef.current.focus();
    // console.log(inputRef);
  }, []);

  const login = () => {
    alert(`환영합니다 ${inputRef.current.value}`);
    inputRef.current.focus();
  };
  return (
    <div>
      <input type="text" placeholder="username" ref={inputRef} />
      <button onClick={login}>로그인</button>
    </div>
  );
}

위의 코드를 해석해보면, App 이라는 컴포넌트 안에 우선 inputRef 라는 변수를 선언해 useRef( ) 를 만들어준다.

그리고, useEffect 를 사용해서 화면이 렌더링되면은 inputRef 라는

useRef( ).current.focus( ) 를 활용해 input 태그에다가 focus 를 할 수 있다.

그리고 login 함수를 선언해, alert 함수를 이용해서 button 태그를 누를때 마다

환영합니다 '안녕' <- 이 때, 안녕은 input 에 작성한 value 이다.

화면에 뜰 수 있도록 해준다.

그리고, 마지막으로 다시

inputRef.current.focus()

해줘서 input 태그를 focus 해주게 한다.

결과는...

로그인 버튼을 누르면...

이렇게 alert 가 뜨면서, input 에 작성한 값이 나오게 된다.

확인을 누르면...

이렇게 focus 가 된 상태로 바뀐다.

그리고 중요한 사실은

  • useRef 를 사용할려면, input 태그 안에 ref={ } 속성을 만들어서 선언한 변수를 넣어준다. (예... ref={inputRef} )

  • 주로 input 태그를 활용할 때, 많이 쓰인다.

✨ useContext

이 Hook 은 상위에 있는 prop 같은 데이터들을 빠르게 전달할 수 있도록 도와준다.

그 말은, 주로 다양한 레벨에 있는 많은 컴포넌트들에게 전역적인 데이터를 전달하기 위한 용도로 쓰인다.

출처 : https://clucas0311.medium.com/usecontext-react-hooks-be7fd21dce89

위의 이미지를 참고하면...

컴포넌트 데이터들을 건너 건너 전달해야 하는데,

Context 를 사용하면, 한 번에 상위에 있는 데이터를 맨 밑에 있는 컴포넌트로도 전달이 가능하다.

하지만 Context 는 필요할 때만 사용해야 한다!

  • Context 를 사용하면 컴포넌트를 재사용하기 어려워 질 있다.
  • 그리하여, Prop drilling 을 피하기 위한 목적이면, Component Compositioin (컴포넌트 합성)을 먼저 고려해보자.

Prop Drilling이란, props를 오직 하위 컴포넌트로 전달하는 용도로만 쓰이는 컴포넌트를 거치면서 컴포넌트에서 다른 컴포넌트로 데이터를 전달하는 과정을 말한다.

그리하여, 예를들면...

처음에 src 에 context 라는 디렉토리를 생성해서, context 객체를 만들어준다.

색을 전달하는 -> ThemeContext.js
사용자 이름을 전달하는 -> UserContext.js

ThemeContext.js

import { createContext } from "react";

export const ThemeContext = createContext(null);

처음에 import 를 해줘서, createContext 를 불러와야 한다.

그리고 전달한 변수를 만들어서, 선언시켜준다.

이 때, createContext( ) <- 괄호 안에는 초기값을 넣어준다.

UserContext.js

import { createContext } from "react";

export const UserContext = createContext(null);

똑같이 createContext 를 불러와, 초기값으로는 null 을 넣어준다.

그리고 App.js 에 불러온다.

중요한 사실!

  • Context 객체를 구독하고 있는 컴포넌트를 렌더링할 때 React는 트리 상위에서 가장 가까이 있는 짝이 맞는 Provider로부터 현재값을 읽어준다.
  • Provider 하위에서 context 를 구독하는 모든 컴포넌트는 Provider 의 value prop 가 바뀔 때마다 다시 렌더링 된다.

App.js

import { useState } from "react";
import Page from "./components/Page";
import "./styles.css";
import { ThemeContext } from "./context/ThemeContext";
import { UserContext } from "./context/UserContext";

export default function App() {
  const [isDark, setIsDark] = useState(false);
  return (
    <UserContext.Provider value={"사용자"}>
      <ThemeContext.Provider value={{ isDark, setIsDark }}>
        <Page />
      </ThemeContext.Provider>
    </UserContext.Provider>
  );
}

처음에는 useState 를 만들어, 하위 컴포넌트들한테 전달할 상태값을 만들어준다.

*** 이 때, Provider 컴포넌트는 value prop을 받아서 이 값을 하위에 있는 컴포넌트에게 전달한다.

그리하여, UserContext 는 value 로 '사용자' 문자열을 전달하고...
ThemeContext 는 value 로 객체로 useState 에 있는 상태값과 함수를 전달해준다.

그러면 Page 컴포넌트로 넘어가서...

Page.jsx

import Content from "./Content";
import Footer from "./Footer";
import Header from "./Header";

function Page() {
  return (
    <div className="page">
      <Header />
      <Content />
      <Footer />
    </div>
  );
}

export default Page;

Header, Content, Footer 라는 컴포넌트들을 import 해서, div 태그 안에 넣어준다.

처음으로 Header.jsx 는...

Header.jsx

import { useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";
import { UserContext } from "../context/UserContext";

function Header() {
  const { isDark } = useContext(ThemeContext);
  const user = useContext(UserContext);

  console.log(user);
  return (
    <header
      className="header"
      style={{
        backgroundColor: isDark ? "black" : "lightgray",
        color: isDark ? "white" : "black"
      }}
    >
      <h1>Welcome {user}!</h1>
    </header>
  );
}

export default Header;

만들어둔 ThemeContext 와 UserContext 를 불러와주고...

구조 분해 문법을 사용해서 중괄호로 isDark 를 넣어주고, useContext hook 을 사용해서 안에는 만들어둔 우리의 Context 객체를 넣어준다.

UserContext 는 굳이 구조 분해를 안해도 된다.

그리하여, 코드를 해석하면 header 스타일에서 isDark 가 true 이면, 배경색은 검정색이고 false 이면 연한 회색이다.

똑같이, 폰트 색깔도 true 이면 하얀색, false 이면 검정색이다.

그리고 h1 태그 안에 중괄호를 해서 user 를 즉, Context 객체에 있는 데이터를 전달한다.


다음으로...

Content.jsx

import { useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";
import { UserContext } from "../context/UserContext";

function Content() {
  const { isDark } = useContext(ThemeContext);
  const user = useContext(UserContext);
  return (
    <div
      className="content"
      style={{
        backgroundColor: isDark ? "black" : "white",
        color: isDark ? "white" : "black"
      }}
    >
      <p>{user}님, 좋은 하루 되세요</p>
    </div>
  );
}

export default Content;

Header 컴포넌트에서 만든 코드와 매우 흡사하다. (아니 그냥 똑같다)


마지막으로 Footer.jsx 로 가보면...

Footer.jsx

import { useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";

function Footer() {
  const { isDark, setIsDark } = useContext(ThemeContext);
  const toggleTheme = () => {
    setIsDark(!isDark);
  };
  return (
    <footer
      className="footer"
      style={{ backgroundColor: isDark ? "black" : "lightgray" }}
    >
      <button className="button" onClick={toggleTheme}>
        Dark Mode
      </button>
    </footer>
  );
}

export default Footer;

footer 에는 button 을 만들어줘서, 누를 때마다 색이 바뀌도록 설계해준다.

Header 와 Content 랑 비슷하게, isDark 를 불러오지만 이번엔 함수인 setIsDark 도 불러오고 UserContext 는 생략한다.

그리고 컴포넌트 안에 함수를 만들어서, setIsDark 함수안에 isDark 상태값을 반대로 만든다.

원래 상태값이 false 이면, true 로 바뀌고
true 이면 false 로 바뀐다.

버튼을 누를때마다, 화면의 색깔과 폰트의 색이 바뀐다.

기본 형태

Dark Mode 버튼을 누르면...

화면이 검정색으로 바뀌면서 폰트는 하얀색으로 바뀐다.

하지만 이렇게 편리한 기능처럼 보여도, 단점은 늘 존재한다!

단점

  • 컴포넌트 계층이 많아질 수록 props 를 전달만하는 코드를 계속해서 작성해야한다
  • props 의 변화가 없음에도 리렌더링이 이루어질 수 있다.

끝으로 :

  • 카페에서 이렇게 리액트 훅을 공부하니, 감회가 새롭고 그 전에 이해가 되지 않은 부분들이 해결되었다.
profile
하루를 의미있게 살자!

0개의 댓글