위의 이미지의 익스텐션을 설치하기
yarn add styled-components
const StBox = styled.div`
width: 100px;
height: 100px;
border: 1px solid red;
margin: 20px;
`;
☞ 먼저 const 선언 해주고 ``(백틱)을 써서 그 안에 CSS를 넣어준다.
function App() {
return <StBox>안녕하세요</StBox>;
}
import styled from "styled-components";
const StBox = styled.div`
width: 100px;
height: 100px;
border: 1px solid ${(props) => props.borderColor};
margin: 20px;
`;
const StP = styled.p`
color: purple;
`;
function App() {
return (
<>
<StBox borderColor="red">
<StP>안녕 빨간박스</StP>
</StBox>
<StBox borderColor="blue">
<StP>안녕 파란박스</StP>
</StBox>
<StBox borderColor="green">
<StP>안녕 초록박스</StP>
</StBox>
</>
);
}
export default App;
☞ 이런식으로 조건부 스타일링이 가능해서 용이함
import styled from "styled-components";
const StContainer = styled.div`
display: flex;
`;
const StBox = styled.div`
width: 100px;
height: 100px;
border: 1px solid ${(props) => props.borderColor};
margin: 20px;
`;
const StP = styled.p`
color: purple;
`;
//박스의 색
const boxList = ["red", "blue", "green", "black"];
//색을 넣으면 이름을 반환
const getBoxName = (color) => {
switch (color) {
case "red":
return "빨간 박스";
case "green":
return "초록박스";
case "blue":
return "파란박스";
default: /// 아무것도 아니면 검은색박스!
return "검은박스";
}
};
function App() {
return (
<StContainer>
{boxList.map((box) => {
return (
<StBox borderColor={box}>
<StP>안녕 {getBoxName(box)}</StP>
</StBox>
);
})}
</StContainer>
);
}
export default App;
☞ return 쪽에 {자바스크립트} 넣어주면 활용이 가능함
//GlobalStyle.jsx
import { createGlobalStyle } from "styled-components";
const GlobalStyle = createGlobalStyle`
body{
font-family: "나눔고딕", "Arial", sans-serif;
line-height: 1.5;
}
`;
export default GlobalStyle;
//App.jsx
import GlobalStyle from "./components/GlobalStyle";
return
<GlobalStyle />
☞ 기존의 컴포넌트처럼 동일하게 사용가능함
HTML 태그들(div, p, h1 등)은 기본적으로 스타일이 적용되어 있어, padding, margin, 폰트 크기 등을 별도로 지정하지 않아도 미리 설정 되어있음
각 브라우저마다 이 기본 스타일이 약간씩 다르게 적용되어 있음.
일관된 스타일을 유지하기 위해 reset.css를 사용할 수 있어서 어느 브라우저에서나 일정한 디자인이 적용됨
//적용할 곳에 상위에 쓸 것
import "./reset.css";
//reset.css
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
const [state, setState] = useState(초기값);
import { useState } from "react";
import "./App.css";
function App() {
const [number, setNumber] = useState(0);
return (
<>
<div>Number State : {number}</div>
<button
onClick={() => {
//기존 방식 setNumber(number + 1);
//함수형 업데이트
setNumber((currentNumber) => {
return currentNumber + 1;
});
}}
>
누르면 UP
</button>
</>
);
}
export default App;
// 일반적인 사용법
import { useState } from "react";
const App = () => {
const [number, setNumber] = useState(0);
return (
<div>
<div>{number}</div>
<button
onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}
>
누르면 UP
</button>
</div>
);
}
export default App;
//함수형 사용법
import { useState } from "react";
const App = () => {
const [number, setNumber] = useState(0);
return (
<div>
<div>{number}</div>
<button
onClick={() => {
setNumber((previousState) => previousState + 1);
setNumber((previousState) => previousState + 1);
setNumber((previousState) => previousState + 1);
}}
>
누르면 UP
</button>
</div>
);
}
export default App;
☞ 두개 다 버튼을 클릭해보면 일반적인 사용법을 사용했을 때는 아무리 눌러도 1이 된다. 하지만 함수형을 사용하면 3번 반영이 된다.
[부연설명]
1) 일반적인 사용법 방식:
2) 함수형 사용법 방식:
import React, { useEffect } from "react";
const App = () => {
useEffect(() => {
console.log("hello useEffect");
});
return <div>useEffect</div>;
};
1) 배열이 비어 있을때
import { useEffect, useState } from "react";
import "./App.css";
function App() {
const [value, setValue] = useState("");
useEffect(() => {
console.log(`hello useEffect : ${value}`);
}, []); //← 여기 []
return (
<div>
<input
type="text"
value={value}
onChange={(event) => {
setValue(event.target.value);
}}
/>
</div>
);
}
export default App;
☞ 의존성 배열이 빈 배열인 경우, useEffect는 최초 렌더링 후 한 번만 실행됨
2) 배열에 값이 있을 때
import { useEffect, useState } from "react";
import "./App.css";
function App() {
const [value, setValue] = useState("");
useEffect(() => {
console.log(`hello useEffect : ${value}`);
}, [value]); // [value]가 값이 들어 가 있는 것
return (
<div>
<input
type="text"
value={value}
onChange={(event) => {
setValue(event.target.value);
}}
/>
</div>
);
}
export default App;
☞ 의존성 배열에 값이 있는 경우, 해당 값이 변경될 때마다 useEffect가 실행됨
import { useEffect, useState } from "react";
import "./App.css";
function App() {
const [value, setValue] = useState("");
useEffect(() => {
console.log(`hello useEffect : ${value}`);
return ( //여기서 부터 클린업
() => {
console.log("곧 사라집니다.");
}, // 여기까지 클린업
[value]
);
});
return (
<div>
<input
type="text"
value={value}
onChange={(event) => {
setValue(event.target.value);
}}
/>
</div>
);
}
export default App;
☞ useEffect 내부에서 return을 통해 클린 업 함수를 입력하면, 컴포넌트가 사라질 때 해당 함수가 실행됨
import { useRef } from "react";
const ref = useRef("초기값");
☞ ref에 저장된 값은 렌더링을 일으키지 않고, 컴포넌트가 다시 렌더링되어도 값이 유지된다.
import { useEffect, useRef } from "react";
import "./App.css";
function App() {
const idRef = useRef(""); //이렇게 선언하면 아래 input을 특정할 수 있다.
useEffect(() => {
idRef.current.focus(); // 포커스 하게 하는 코드
}, []);
return (
<>
<div>
아이디 : <input type="text" ref={idRef} />
</div>
<div>
비밀번호 : <input type="password" />
</div>
</>
);
}
export default App;
import { useEffect, useRef, useState } from "react";
import "./App.css";
function App() {
const idRef = useRef("");
const pwRef = useRef("");
const [id, setId] = useState("");
useEffect(() => {
idRef.current.focus();
//pwRef.current.focus();
}, []);
useEffect(() => {
if (id.length >= 10) {
pwRef.current.focus();
}
}, [id]);
return (
<>
<div>
아이디 :{" "}
<input
type="text"
ref={idRef}
value={id}
onChange={(e) => {
setId(e.target.value);
}}
/>
</div>
<div>
비밀번호 : <input type="password" ref={pwRef} />
</div>
</>
);
}
export default App;
1) ID 감지를 위해 value와 onChange 사용:
value는 입력 필드에 표시되는 값을 나타냄.
onChange는 입력 필드 값 변경 시 호출되며, 변경된 값을 사용하여 ID 상태를 업데이트함.
2) useEffect로 조건부 필터링:
useEffect를 사용하여 특정 조건(ID의 길이가 10이상되면 다른 입력 필드로 이동)을 감지함.
왜 필요한가?
Prop drilling 문제:
데이터를 부모 컴포넌트에서 자식 컴포넌트로 전달할 때, 깊이가 깊어지면 추적이 어려워지고 오류 대응이 어려움.
Context API 필수 개념
//GrandFather.jsx
import React from "react";
import Father from "./Father";
function GrandFather() {
const houseName = "스파르타";
const pocketMoney = 10000;
return <Father houseName={houseName} pocketMoney={pocketMoney} />;
}
export default GrandFather;
//Father.jsx
import React from "react";
import Child from "./Child";
function Father({ houseName, pocketMoney }) {
return <Child houseName={houseName} pocketMoney={pocketMoney} />;
}
export default Father;
//Child.jsx
import React from "react";
function Child({ houseName, pocketMoney }) {
const stressedWord = {
color: "red",
fontWeight: "900",
};
return (
<div>
나는 이 집안의 막내에요.
<br />
할아버지가 우리 집 이름은 <span style={stressedWord}>{houseName}</span>
라고 하셨어요.
<br />
게다가 용돈도 <span style={stressedWord}>{pocketMoney}</span>원만큼이나 주셨답니다.
</div>
);
}
export default Child;
☞ 프롭스를 이용해서 부모 컴포넌트에서 자식 컴포넌트로 데이터 전달을 했었는데 깊이가 깊어지면 관리하기에 어려움
[새로운 useContext]
//[새롭게 생성]FamilyContext.js
import { createContext } from "react";
export const FamilyContext = createContext(null);
//GrandFather.jsx
import React from "react";
import Father from "./Father";
import { FamilyContext } from "../context/FamilyContext";
function GrandFather() {
const houseName = "스파르타";
const pocketMoney = 10000;
return (
<FamilyContext.Provider value={{ houseName, pocketMoney }}>
<Father />
</FamilyContext.Provider>
);
}
export default GrandFather;
//Father.jsx
import React from "react";
import Child from "./Child";
function Father() {
return <Child />;
}
export default Father;
//Child.jsx
import React, { useContext } from "react";
import { FamilyContext } from "../context/FamilyContext";
function Child({ houseName, pocketMoney }) {
const stressedWord = {
color: "red",
fontWeight: "900",
};
const data = useContext(FamilyContext);
console.log("data", data);
return (
<div>
나는 이 집안의 막내에요.
<br />
할아버지가 우리 집 이름은 <span style={stressedWord}>{data.houseName}</span>
라고 하셨어요.
<br />
게다가 용돈도 <span style={stressedWord}>{data.pocketMoney}</span>원만큼이나 주셨답니다.
</div>
);
}
export default Child;
export const FamilyContext = createContext(null);
// GrandFather.jsx
import React from "react";
import Father from "./Father";
import { FamilyContext } from "../context/FamilyContext";
function GrandFather() {
const houseName = "스파르타";
const pocketMoney = 10000;
return (
<FamilyContext.Provider value={{ houseName, pocketMoney }}>
<Father />
</FamilyContext.Provider>
);
}
export default GrandFather;
import React from "react";
import Child from "./Child";
function Father() {
return <Child />;
}
export default Father;
// Father.jsx
import React from "react";
import Child from "./Child";
function Father() {
return <Child />;
}
export default Father;
오늘의 한줄평 : 와....