✔️ 리액트 복습!
유튜브 별코딩님의 강의를 보고 따라만든 나의 리액트 프로젝트
우리가 자바스크립트에서는 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 태그를 활용할 때, 많이 쓰인다.
이 Hook 은 상위에 있는 prop 같은 데이터들을 빠르게 전달할 수 있도록 도와준다.
그 말은, 주로 다양한 레벨에 있는 많은 컴포넌트들에게 전역적인 데이터를 전달하기 위한 용도로 쓰인다.
출처 : https://clucas0311.medium.com/usecontext-react-hooks-be7fd21dce89
위의 이미지를 참고하면...
컴포넌트 데이터들을 건너 건너 전달해야 하는데,
Context 를 사용하면, 한 번에 상위에 있는 데이터를 맨 밑에 있는 컴포넌트로도 전달이 가능하다.
하지만 Context 는 필요할 때만 사용해야 한다!
Prop Drilling이란, props를 오직 하위 컴포넌트로 전달하는 용도로만 쓰이는 컴포넌트를 거치면서 컴포넌트에서 다른 컴포넌트로 데이터를 전달하는 과정을 말한다.
그리하여, 예를들면...
처음에 src 에 context 라는 디렉토리를 생성해서, context 객체를 만들어준다.
색을 전달하는 -> ThemeContext.js
사용자 이름을 전달하는 -> UserContext.js
import { createContext } from "react";
export const ThemeContext = createContext(null);
처음에 import 를 해줘서, createContext 를 불러와야 한다.
그리고 전달한 변수를 만들어서, 선언시켜준다.
이 때, createContext( ) <- 괄호 안에는 초기값을 넣어준다.
import { createContext } from "react";
export const UserContext = createContext(null);
똑같이 createContext 를 불러와, 초기값으로는 null 을 넣어준다.
그리고 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 컴포넌트로 넘어가서...
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 는...
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 객체에 있는 데이터를 전달한다.
다음으로...
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 로 가보면...
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 버튼을 누르면...
화면이 검정색으로 바뀌면서 폰트는 하얀색으로 바뀐다.
하지만 이렇게 편리한 기능처럼 보여도, 단점은 늘 존재한다!
단점
끝으로 :