yarn create react-app 명령어를 통해 리액트 앱 폴더를 생성할 수 있다.yarn start 명령어를 사용하면 해당 폴더의 리액트 웹 앱을 구동시켜준다.# yarn create react-app 이름
yarn create react-app ch01
yarn start
VScode에서 실행 오류 디버깅
💡 보안 상의 이유로 vscode에서 powershell로 yarn start 명령어가 불가능하다. cmd 창으로 바꾸어 yarn start를 실행하자
//rafce
import React from 'react'
const Test2 = () => {
return (
<div>Test2</div>
)
}
export default Test2
// rfc
import React from 'react'
export default function Test2() {
return (
<div>Test2</div>
)
}
// rcc
import React, { Component } from 'react'
export default class Test6 extends Component {
render() {
return (
<div>Test6</div>
)
}
}
리액트는 html이 아닌 js를 핵심으로 작성한다. 그러나 파일 확장자명이 js이더라도, 실제 파일은 jsx이다. jsx란 자바스크립트의 확장 문법으로 바벨을 사용하여 일반 자바스크립트 형태의 코드로 변환된다. jsx는 js와 html을 혼용하여 사용할 수 있다. 하지만 jsx 안에서 html 문법이 완전히 같지는 않다.
// 잘못된 예시
<h1>Title1</h1>
<h2>Title2</h2>
// 옳은 예시
<div>
<h1>Title1</h1>
<h2>Title2</h2>
</div>
const name = "Kim";
return (
<>
<h1>Name is {name}</h1>
</>
)
const style = {
backgroundColor: "red"
}
<h1 style={style}>backgroundColor</h1>
<h2 style={{backgroundColor: "blue"}}>inline style</h2>
// html에서
<input type="text">
// jsx에서
<input type="text"></input>
<input type="text" /> // 이러한 방식을 self-closing 태그라 한다.
컴포넌트 이름은 대문자로 시작한다.
render() { html 내용 } 함수가 반드시 필요하다.// rce
import React, { Component } from 'react'
export class Test6 extends Component {
render() {
return (
<div>Test6</div>
)
}
}
export default Test6
// rfce
function Test6() {
return (
<div>Test6</div>
)
}
export default Test6
컴포넌트의 속성을 설정할 때 사용하는 요소로 기본값을 지정하거나, 부모 컴포넌트에서 호출할 때 값을 설정해 줄 수 있다.
props.children: 컴포넌트 태그 사이의 내용을 보여준다.// rafcp
const Child = props => {
return (
<div>
<h1>{props.name}</h1>
<div>{props.children}</div>
</div>
)
}
Test6.defaultProps = {
name: "기본이름"
}
export default Child
-----
import Child from './Child';
const Parent= () => {
return (
<Child name="react" />;
<Child>this is prop.children </Child>;
)
}
const Child = ({name, children}) => {
return (
<div>
<h1>{props.name}</h1>
<div>{props.children}</div>
</div>
)
}
Test6.defaultProps = {
name: "기본이름"
}
export default Child
컴포넌트 내부에서 바뀔 수 있는 값으로, 클래스형 컴포넌트의 state와 함수 컴포넌트의 state, useState가 있다.
일종의 변수이다. let과 var같은 경우도 사용 가능하고 값도 변경가능하지만, 자동으로 렌더링을 갱신하지 않는다. 즉, 실제로는 값이 바뀔지라도 화면 상에서는 바뀌지 않는다. 반면 state나 props의 경우 리액트에서 자동으로 변경된 데이터를 감지하고 다시 렌더링해준다.
- state의 값은 setState 혹은 useState의 setter 함수를 통해서만 값을 바꾸어야 한다.
constructor(props){ } 생성자 메서드를 작성하여 state를 설정할 수 있다. 이때 반드시 super(props)를 호출해야 한다.this.state로 클래스 컴포넌트의 state를 조회할 수 있다. state는 json 객체 타입이어야 한다.this.setState()로 클래스 컴포넌트의 state 값을 변경할 수 있다.import {Component} from'react';
// 클래스 형의 state(상태정보)
class Test8 extends Component{
constructor(props){
super(props);
this.state = {
increaseNumber: 0,
decreaseNumber: 0,
};
}
render(){
const {increaseNumber, decreaseNumber} = this.state;
return <div className="App">
<h1>증가하는 값 : {increaseNumber}</h1>
<h1>감소하는 값 : {decreaseNumber}</h1>
<button style={{ padding: '30px' }}
onClick={()=>{
this.setState({
increaseNumber: increaseNumber + 1,
decreaseNumber: decreaseNumber - 1,
});
}}
> button </button>
</div>
}
}
export default Test8
class Test8 extends Component{
state = {
increaseNumber: 0,
decreaseNumber: 0,
}
render(){
const {increaseNumber, decreaseNumber} = this.state;
return <div className="App">
<h1>증가하는 값 : {increaseNumber}</h1>
<h1>감소하는 값 : {decreaseNumber}</h1>
<button style={{ padding: '30px' }}
onClick={()=>{
this.setState({
increaseNumber: increaseNumber + 1,
decreaseNumber: decreaseNumber - 1,
});
}}
> button </button>
</div>
}
}
export default Test8
this.setState(prevState => {
return {number: prevState.number + 1};
})
this.setState(
{number: number+1},
() => {
console.log("number가 증가했습니다");
}
)
함수형 컴포넌트에서는 useState라는 훅(Hooks) 사용해 state와 this.setState를 커스터마이징 할 수 있다. 클래스형 컴포넌트의 state와 달리 함수형 컴포넌트의 useState에서는 객체 외에도 다양한 자료형의 값을 넣을 수 있다.
import React, {useState} from 'react'
const Test9 = () => {
const [message, setMessage] = useState('');
const onClickEnter = () => setMessage("환영");
const onClickLeave = () => setMessage("바이");
const [color, setColor] = useState("black");
return (
<div className="App">
<h1>Test9</h1>
<button onClick={onClickEnter}>입실</button>
<button onClick={onClickLeave}>퇴실</button>
<h1 style={{color}}>{message}</h1>
<button onClick={() => setColor('gold')}>금</button>
</div>
)
}
export default Test9
arr.map 함수를 사용하여 return문 내에서 반복문을 사용할 수 있다.import React from 'react'
const Test3 = () => {
const arr = [1, 2, 3, 4, 5, 6, 7];
return (
<div className="App">
<ul>
{
arr.map((item, index) => {
return <li>{item}</li>
})
}
</ul>
</div>
)
}
export default Test3
function App() {
const weekArr = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"];
const rendering = () => {
const result = [];
for (let i = 0; i < weekArr.length; i++) {
result.push(<span key={i}>{weekArr[i] + " / "}</span>);
}
return result;
};
return <div>{rendering()}</div>;
}
// arrow function으로 정의 가능
<button onClick={() => { this.setState({message:''})}}>지우기</button>
// 그냥 function은 불가능
<button onClick={function() {this.setState({message: ''})}}}>지우기</button>
// arrow 함수 변수 사용 가능
const onDelete = () => { this.setState({message:''}); };
<button onClick={onDelete}>지우기</button>
// arrow 함수 변수를 호출하는 것을 불가능. 렌더링되는 시점에 호출되기 때문에 비정상 작동한다.
const onDelete = () => { this.setState({message:''}); };
<button onClick={onDelete()}>지우기</button>
// 그냥 함수 변수 사용 불가능
const onDelete2 = function () { this.setState({ message: "" }); };
<button onClick={onDelete2}>지우기</button>
Hook은 함수 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 “연동(hook into)“할 수 있게 해주는 함수입니다. Hook은 class 안에서는 동작하지 않습니다. 대신 class 없이 React를 사용할 수 있게 해주는 것입니다.
useState(초기값) : 렌더링되는 변수 state와 그 state를 세팅하는 setState가 반환된다.import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
💡 리액트의 훅은 값이 갱신되는 것이 아니라 대체되는 것이다. 즉 새로 생성되는 거나 마찬가지고, 따라서 배열이나 객체의 값을 수정할 때는 바로 해당 배열이나 객체에 값을 넣는 것이 아니라, 기존 값을 가져와서 수정 후 다시 대입해주어야 한다.
.concat(새로운 값)을 사용한다. 제거할 때는 .filter(제거할 조건)을 사용한다.import React, { useState } from "react";
//useState를 이용한 객체의 배열 추가/제거
const Test2 = () => {
const [names, setNames] = useState([
{ id: 1, text: "박진권" },
{ id: 2, text: "신승원" },
{ id: 3, text: "백준철" },
{ id: 4, text: "구예진" }
]);
const [inputText, setInputText] = useState("");
const [nextId, setNextId] = useState(5);
const onChange = (e) => {
setInputText(e.target.value);
};
const onClick = (e) => {
const nextNames = names.concat({
//하나의 객체 생성
id: nextId,
text: inputText
});
setNextId(nextId + 1); //아이디를 하나 증가
setNames(nextNames); //객체를 배열에 추가
setInputText("");
};
const onRemove = (id) => {
const nextNames = names.filter((data) => data.id !== id);
setNames(nextNames);
};
const namesList = names.map((data) => (
<li key={data.id} onDoubleClick={() => onRemove(data.id)}>
{" "}
{data.id}: {data.text}
</li>
));
return (
<div className="App">
<input value={inputText} onChange={onChange} />
<button onClick={onClick}>추가</button>
<ul className="list">{namesList}</ul>
</div>
);
};
export default Test2;
import React, { useState } from "react";
function ObjectExample() {
const [person, setPerson] = useState({ name: "John", age: 30 });
const updateAge = () => {
// 객체의 복사본을 만들어서 업데이트합니다.
const updatedPerson = { ...person, age: person.age + 1 };
setPerson(updatedPerson);
};
return (
<div>
<p>Name: {person.name}</p>
<p>Age: {person.age}</p>
<button onClick={updateAge}>Update Age</button>
</div>
);
}
export default ObjectExample;
import React, { useState } from "react";
function ObjectExample() {
const [student, setStudent] = useState({
id: [1, 2],
name: ["kim1", "kim2"]
});
const updateStudent = () => {
let updatedStudent = {
id: [...student.id, 3],
name: [...student.name, "kim3"]
};
setStudent(updatedStudent);
};
return (
<div>
<p>
{student.id} {student.name}
</p>
<button onClick={updateStudent}>Update Student</button>
</div>
);
}
export default ObjectExample;
javascript에서는 특정 DOM 을 선택해야 하는 상황에 getElementById, querySelector 같은 DOM Selector 함수를 사용해서 DOM 을 선택한다. 이와 같이 리액트에서 특정 DOM 요소를 선택하여 변수를 붙여줄 때 사용하는 것이 ref(reference)이다.
React.createRef()와 같다.import React, { Component } from 'react'
import './Test4.css';
class Test4 extends Component {
input = React.createRef(); //ref 생성
render() {
return (
<div className='App'>
<input type='password' ref={this.input} />
</div>
)
}
}
export default Test4;
useRef(초기값)를 사용한다.import React, { useRef, useEffect } from "react";
function InitialDOMReference() {
// 초기값으로 DOM 요소를 설정하려면 useRef의 인자로 DOM 요소를 전달합니다.
const divRef = useRef(1);
useEffect(() => {
// 컴포넌트가 마운트되면 초기값으로 설정된 div 요소에 스타일을 적용합니다.
if (divRef.current) {
divRef.current.style.backgroundColor = "lightblue";
}
}, []);
return (
<div>
{/* 초기값으로 설정할 div 요소 */}
<div>{divRef.current}</div>
<div ref={divRef}>This is a div element</div>
</div>
);
}
export default InitialDOMReference;
import React, { useState, useEffect, useRef } from 'react';
function ValueComparisonExample() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
// 컴포넌트가 업데이트될 때 이전 count 값을 저장합니다.
prevCountRef.current = count;
}, [count]);
const handleIncrement = () => {
setCount(count + 1);
};
return (
<div>
<p>Current Count: {count}</p>
<p>Previous Count: {prevCountRef.current}</p>
<button onClick={handleIncrement}>Increment</button>
</div>
);
}
export default ValueComparisonExample;
useEffect(() => {
// 부수 효과를 수행할 코드
}, [dependencies]);
import React, { useState, useEffect } from 'react';
function WithDependencies() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]); // count 값이 변경될 때만 useEffect 실행
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default WithDependencies;
import React, { useState, useEffect } from 'react';
function WithoutDependencies() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Effect ran");
}, []); // 빈 배열이므로 컴포넌트가 마운트될 때만 실행
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default WithoutDependencies;
import React from 'react'
import {AgeContext} from './AgeContext'
import {NameContext} from './NameContext'
import Header from './Header'
const Test5 = () => {
return (
<div>
<h1>Test 5</h1>
<AgeContext.Provider value="age of provider">
<NameContext.Provider value="this is name of provider">
<Header />
</NameContext.Provider>
</AgeContext.Provider>
</div>
)
}
export default Test5import React, {createContext} from 'react'
export const AgeContext = createContext(null);import React, {useContext} from 'react'
import { AgeContext} from './AgeContext'
import { NameContext} from './NameContext'
const Header = () => {
const age = useContext(AgeContext);
const user = useContext(NameContext);
return (
<div>
<p>Hello, <strong>{user}</strong>!</p>
<p>You are <strong>{age}</strong> years old.</p>
</div>
)
}
export default Headerconst memoizedValue = useMemo(() => {
// 계산하고 메모이제이션할 값 또는 연산
return result;
}, [dependencies]);
import React, { useState } from 'react';
function Fibonacci({ n }) {
// 피보나치 수열을 계산하는 함수
const calculateFibonacci = (num) => {
console.log(`Calculating Fibonacci(${num})...`);
if (num <= 1) {
return num;
}
let prev = 0;
let current = 1;
for (let i = 2; i <= num; i++) {
const next = prev + current;
prev = current;
current = next;
}
return current;
};
// 매 렌더링마다 중복 계산
const fibonacciNumber = calculateFibonacci(n);
return (
<div>
<p>Fibonacci({n}): {fibonacciNumber}</p>
</div>
);
}
function App() {
const [fibNumber, setFibNumber] = useState(10);
const [number, setNumber] = useState(0);
return (
<div>
<input
type="number"
value={fibNumber}
onChange={(e) => setFibNumber(Number(e.target.value))}
/>
<Fibonacci n={fibNumber} />
<p>{number}</p>
<button onClick={()=>{setNumber(number+1)}}>increase Number</button>
</div>
);
}
export default App;import React, { useState, useMemo } from "react";
function Fibonacci({ n }) {
// 피보나치 수열을 계산하고 메모이제이션
const fibonacciNumber = useMemo(() => {
console.log(`Calculating Fibonacci(${n})...`);
if (n <= 1) {
return n;
}
let prev = 0;
let current = 1;
for (let i = 2; i <= n; i++) {
const next = prev + current;
prev = current;
current = next;
}
return current;
}, [n]);
return (
<div>
<p>
Fibonacci({n}): {fibonacciNumber}
</p>
</div>
);
}
function App() {
const [fibNumber, setFibNumber] = useState(10);
const [number, setNumber] = useState(6);
return (
<div>
<h1>App</h1>
<input
type="number"
value={fibNumber}
onChange={(e) => setFibNumber(Number(e.target.value))}
/>
<Fibonacci n={fibNumber} />
<p>{number}</p>
<button onClick={()=>{setNumber(number+1)}}>number increase</button>
</div>
);
}
export default App;현재 상태변수(state) 객체와 행동(action) 객체를 인자로 받아, 새로운 상태를 반환하는 훅. useState보다 더 복잡하고, 다양한 변수나 객체를 관리할 때 사용한다. useState와 비슷한 역할을 하지만 더 많은 제어와 구조화된 상태 관리를 가능하게 한다.
state: 리듀서 함수를 통해 관리되는 현재 상태입니다.dispatch: 액션을 디스패치하는 함수입니다. 이 함수를 호출하여 상태를 변경할 수 있습니다.reducer: 리듀서 함수로, 현재 상태와 액션을 받아 새로운 상태를 반환하는 함수입니다.initialState: 초기 상태로, 컴포넌트가 처음 렌더링될 때 사용됩니다.const [state, dispatch] = useReducer(reducer, initialState);
import React, { useReducer } from 'react';
// 리듀서 함수
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
};
function Counter() {
// useReducer를 사용하여 상태와 디스패치 함수를 가져옴
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
</div>
);
}
export default Counter;
함수를 재활용하기 하기 위한 훅(hook)으로 함수를 메모이제이션하고 필요할 때만 새로 생성되도록 도와준다.
💡 실제로 함수가 재생성되는지 확인하는 것이 어렵다. 크롬 웹스토어에서 React DevTools을 이용해서 렌더링되는 항목을 하이라이트해서 볼 수 있다고 한다.memoizedCallback: 메모이제이션된 콜백 함수입니다. 이 함수는 렌더링 시에 재사용됩니다.callback: 메모이제이션하고자 하는 콜백 함수입니다.dependencies (선택사항): 콜백 함수가 의존하는 값들의 배열입니다. 배열에 포함된 값 중 하나라도 변경되면, 메모이제이션된 함수가 새로 생성됩니다.const memoizedCallback = useCallback(callback, dependencies);
React-router-dom은 웹 애플리케이션의 경로 및 파라미터, 구조 등을 연결될 수 있도록 하는 훅(hook)의 모음체이다. BrowserRouter > Routes > Route 순의 계층을 이룬다.
BrowserRouter는 React Router의 주요 컴포넌트 중 하나로, HTML5 History API를 사용하여 브라우저의 URL을 관리합니다. 이 컴포넌트를 앱의 최상위 레벨에서 사용하면 라우팅을 설정할 수 있습니다.Routes 컴포넌트를 사용하면 라우트를 중첩 구조로 정의할 수 있으며, 각 라우트에 대한 조건을 기반으로 라우팅을 처리할 수 있습니다.Route 컴포넌트는 특정 URL 경로와 일치하는 경우에 해당 컴포넌트를 렌더링하는 역할을 합니다. path 와 사용하여 일치시킬 경로를 지정하고, **element** 를 사용하여 해당 경로와 일치할 때 렌더링할 컴포넌트를 지정합니다.Outlet을 이용해 Layout을 짤 수 있다. Layout이 될 상위 Route의 페이지에 Outlet을 넣어주면, Outlet 자리에 하위 Route 페이지의 내용이 들어간다.import './App.css';
import React, { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Layout from './Layout';
import Home from './pages/Home';
import About from './pages/About';
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
</Route>
</Routes>
</Router>
);
}
export default App;
Link 컴포넌트는 페이지 간의 내비게이션을 쉽게 구현할 수 있도록 도와주는 컴포넌트입니다. 주로 애플리케이션 내에서 다른 페이지로 이동하거나 특정 경로로 이동하기 위해 사용됩니다. to props를 설정해 Route로 설정된 특정 페이지로 이동useNavigate: 자바스크립트와 같은 페이지 이동 또는 URL 제어와 관련한 rrd의 훅(hook)Navigate: Link+replace. Route로 설정된 특정 페이지로 이동. 주로 이전 페이지, 다음 페이지로 이동하거나 특정 경로로 이동하고자 할 때 사용합니다.import React from 'react'
import { Outlet, useNavigate, Link } from 'react-router-dom';
const Layout = () => {
const navigate = useNavigate();
const goBack = () => { navigate(-1); };
const goHome = () => { navigate('/', { replace : true }); }
//const isLoggedIn = false;
if (!isLoggedIn) {
return <Navigate to="/login" replace={true} />;
}
return (
<div>
<header style={{ background:'#ececec', padding:20, fontSize:24 }}>
<button onClick={goBack}>뒤로가기</button>
<button onClick={goHome}>홈으로</button>
<ul style={{ float:'right' }}>
<li><Link to='/articles'>게시판</Link></li>
<li><Link to='/login'>로그인</Link></li>
<li><Link to='/mypage'>마이페이지</Link></li>
</ul>
</header>
<main>
<Outlet />
</main>
</div>
)
}
export default Layout
yarn add sass
yarn add open-color include-media
yarn add classname
yarn add styled-component
Sass(시스루 CSS)는 CSS의 확장된 버전으로, 스타일 시트를 보다 효율적으로 작성하고 관리할 수 있도록 도와주는 스타일 언어입니다. Sass는 CSS의 단점을 보완하고, 코드를 더 모듈화하고 가독성 있게 작성할 수 있도록 다양한 기능을 제공합니다.
Sass의 주요 특징과 기능은 다음과 같습니다:
Sass는 .scss 확장자를 가진 파일로 작성되며, 이 파일들은 Sass 컴파일러를 통해 일반 CSS 파일로 변환됩니다. Sass를 사용하려면 먼저 Sass 컴파일러를 설치하고 설정해야 합니다. 이러한 작업을 통해 Sass 코드를 CSS로 변환하고 웹 애플리케이션에서 사용할 수 있습니다.
Sass는 프론트엔드 웹 개발에서 널리 사용되며, 스타일 시트의 유지보수와 확장성을 향상시키는 데 도움을 줍니다. CSS 작업을 보다 효율적으로 수행하고 가독성 있는 코드를 작성할 수 있도록 도와주는 강력한 도구입니다.
open-color은 색상 팔레트를 관리하고 선택할 수 있게 해주는 오픈 소스 색상 팔레트 라이브러리입니다. 이 라이브러리는 웹 개발자들이 프로젝트에서 사용할 색상을 쉽게 선택하고 일관된 디자인을 유지하는 데 도움을 줍니다.
open-color 팔레트는 다양한 색상과 톤을 제공하며, 각 색상은 이름과 함께 기본 색상 (red, blue, green 등)과 더 어두운/더 밝은 버전 (red[0], red[1], red[2], ..., blue[0], blue[1], blue[2], ...)으로 구성됩니다. 이러한 다양한 색상을 사용하여 웹 애플리케이션 또는 웹사이트의 디자인을 만들 수 있습니다.
include-media는 미디어 쿼리를 편리하게 관리하고 사용할 수 있게 해주는 CSS 미디어 쿼리 라이브러리입니다. 이 라이브러리는 반응형 웹 디자인을 구현하는 데 도움을 주며, 다양한 화면 크기와 장치에 대한 스타일을 쉽게 정의하고 적용할 수 있도록 해줍니다.
include-media를 사용하면 CSS 미디어 쿼리를 JavaScript 함수와 유사한 방식으로 작성할 수 있습니다. 이를 통해 코드를 더 읽기 쉽게 만들고 유지보수를 용이하게 할 수 있습니다.
주요 특징과 사용법은 다음과 같습니다:
include-media를 사용하여 원하는 미디어 쿼리를 정의하고 이름을 부여할 수 있습니다. 이를 통해 미디어 쿼리를 재사용할 수 있습니다.media.between('400px', '800px')와 같이 사용할 수 있습니다.include-media를 사용하여 특정 미디어 쿼리가 현재 브라우저 환경에서 만족되는지 확인할 수 있습니다.media.between('400px', '800px')를 사용하여 400px에서 800px 사이의 미디어 쿼리를 만들 수 있습니다.include-media는 CSS 미디어 쿼리를 관리하고 사용하기 위한 도구로, 반응형 웹 디자인을 개발하고 구현하는 데 도움을 주며 코드를 더 구조적이고 읽기 쉽게 만듭니다. 이 라이브러리는 JavaScript 환경에서 CSS 미디어 쿼리를 더욱 효과적으로 다루는 데 유용합니다.
styled-components는 JavaScript에서 CSS 스타일을 관리하고 생성하는 데 사용되는 JavaScript 라이브러리입니다. 이 라이브러리는 React 애플리케이션을 개발할 때 매우 인기가 있으며, 컴포넌트 기반 스타일링을 지원하여 컴포넌트와 스타일을 쉽게 결합할 수 있습니다.
styled-components를 사용하면 다음과 같은 주요 기능과 이점을 얻을 수 있습니다:
styled-components를 사용하면 각 React 컴포넌트에 스타일을 연결할 수 있습니다. 스타일은 해당 컴포넌트에 로컬하게 적용되므로 스타일 간의 충돌을 방지하고 유지보수를 쉽게 만듭니다.styled-components를 사용하여 스타일이 적용된 새로운 컴포넌트를 생성할 수 있습니다. 이를 통해 스타일을 재사용하고 컴포넌트를 더욱 모듈화할 수 있습니다.styled-components는 자동으로 벤더 프리픽스를 추가하여 크로스 브라우징을 지원합니다. 따라서 CSS 속성을 작성할 때 벤더별 접두사를 신경 쓸 필요가 없습니다.styled-components는 서버 사이드 렌더링을 지원하여 초기 로드 시에도 올바른 스타일이 적용되도록 합니다.styled-components는 React 생태계에서 널리 사용되며, 많은 개발자와 프로젝트에서 선호되는 스타일링 도구 중 하나입니다. React 컴포넌트와 스타일을 쉽게 통합하고 관리할 수 있으므로, 복잡한 웹 애플리케이션의 스타일링 작업을 단순화하는 데 도움이 됩니다.
styled-components를 사용한 간단한 예시를 보여드리겠습니다. 이 예시에서는 React 컴포넌트에 스타일을 적용하고 커스텀 버튼을 생성하는 방법을 보여줍니다. 먼저, styled-components 라이브러리를 설치합니다:npm install styled-components
# 또는
yarn add styled-components
다음은 예시 코드입니다:import React from 'react';
import styled from 'styled-components';
// 스타일을 정의한 컴포넌트
const StyledButton = styled.button`
background-color: #007bff;
color: #fff;
font-size: 16px;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
background-color: #0056b3;
}
`;
// 스타일이 적용된 버튼을 갖는 컴포넌트
function MyComponent() {
return (
<div>
<h1>Styled Button Example</h1>
<StyledButton>Click Me</StyledButton>
</div>
);
}
export default MyComponent;
이 코드에서는 다음과 같은 작업을 수행하고 있습니다:styled-components에서 styled 함수를 사용하여 스타일이 적용된 StyledButton 컴포넌트를 생성합니다. 이 컴포넌트의 스타일은 템플릿 리터럴을 사용하여 정의되며, 일반적인 CSS와 유사한 구문을 사용합니다.
StyledButton 컴포넌트를 사용하여 버튼을 렌더링합니다. 이 버튼은 StyledButton 컴포넌트의 스타일이 적용됩니다.
버튼에 대한 스타일은 StyledButton 컴포넌트의 속성으로 정의되어 있으므로, 컴포넌트를 재사용하거나 동적으로 스타일을 변경할 수 있습니다.
styled-components를 사용하면 React 컴포넌트와 스타일을 쉽게 통합할 수 있으며, 각 컴포넌트의 스타일을 독립적으로 관리할 수 있습니다. 이를 통해 코드의 가독성과 유지보수성을 향상시킬 수 있습니다.
classname 또는 classnames는 JavaScript 환경에서 CSS 클래스 이름을 조작하고 조합하는 유용한 도구 중 하나입니다. 주로 React 컴포넌트를 개발하거나 다른 JavaScript 환경에서 CSS 클래스를 동적으로 처리할 때 사용됩니다.
주요 용도와 기능은 다음과 같습니다:
React와 함께 사용할 때, 동적으로 클래스를 관리하고 조작하는 데 특히 유용합니다. React 컴포넌트에서 상태나 프롭스에 따라 클래스를 추가하거나 제거하고, 조건부로 스타일을 변경하는 데 활용할 수 있습니다.
classnames 라이브러리를 사용한 몇 가지 예제를 더 제공하겠습니다.조건부 클래스 추가/제거:
import classNames from 'classnames';
const isActive = true;
const isDisabled = false;
const buttonClasses = classNames('button', {
'active': isActive,
'disabled': isDisabled,
});
// 결과: 'button active'
위의 예제에서는 isActive 변수가 true이므로 'active' 클래스가 추가되고, isDisabled 변수가 false이므로 'disabled' 클래스는 추가되지 않습니다.
다중 클래스 결합:
import classNames from 'classnames';
const primaryColor = 'primary';
const additionalClasses = 'extra-class';
const elementClasses = classNames(primaryColor, additionalClasses);
// 결과: 'primary extra-class'
이 예제에서는 두 개의 클래스 이름을 결합하여 하나의 문자열로 만들고 있습니다.
조건부 클래스와 반복 요소:
```jsx
import classNames from 'classnames';
const items = ['item1', 'item2', 'item3'];
const selectedItem = 'item2';
const listClasses = classNames('list', {
'active': selectedItem === 'item2',
});
const itemClasses = items.map((item) =>
classNames('item', {
'selected': item === selectedItem,
})
);
// 결과: list active, item, item selected, item
```
이 예제에서는 반복 요소 목록을 매핑하면서 조건부 클래스를 추가하고 있습니다. 선택된 항목은 'selected' 클래스가 추가되고, 특정 항목은 'active' 클래스가 추가됩니다.
classnames 라이브러리를 사용하면 동적인 클래스 이름 관리를 간편하게 할 수 있으며, React 컴포넌트에서 클래스를 조작하거나 조건부로 스타일을 변경하는 데 유용합니다.