React 배우기 - 상태(State)
1. State
상태란 컴포넌트 내부에서 선언하며 내부에서 값을 변경할 수 있는 데이터를 의미한다.
- State와 Props의 차이
리액트 컴포넌트는 입력과 출력이 있는데 prop를 통해 입력된 데이터를 우리가 만든 컴포넌트 함수가 처리해서 retrun을 통해 출력한다.
props는 컴포넌트를 사용하는 외부자를 위한 데이터이다.
state는 props와 비슷하지만 컴포넌트 내부에서 선언하며 내부에서 값을 변경할 수 있다.
state는 컴포넌트 자신을 위한 데이터이다.
- State의 특징
- 상태는 객체 형태의 데이터이다.
- 상태는 컴포넌트 내부에서 선언되어야 한다.
- 상태는 props와 달리 컴포넌트 내부에서 값을 변경할 수 있다.
- State를 사용하는 이유
- 사용자와의 상호작용을 통해 동적인 웹 페이지를 만들기 위해서 사용한다.
- 상태가 변경되면 컴포넌트는 다시 렌더링된다.
2. State 사용
- 상태를 사용하지 않고 버튼 클릭시 이름 변경
- 상태를 사용하지 않으면 버튼을 클릭해도 이름이 변경되지 않는다.
- console.log()를 통해 name의 값이 변경되는 것을 확인할 수 있다.
// App.js
import React from 'react'
function App() {
let name = 'winter' // name 변수에 'winter'라는 값을 저장한다.
// changeName() 함수를 정의한다.
function changeName() {
// name의 값이 'winter'이면 'fall'로, 'fall'이면 'winter'로 변경한다.
name = name === 'winter' ? 'fall' : 'winter'
console.log(name) // name의 값을 출력한다.
}
return (
// name의 값을 출력한다.
// 버튼을 클릭하면 changeName() 함수를 실행한다.
<div className="root">
<h1>{name}</h1>
<button onClick={changeName}>Name Change</button>
</div>
)
}
export default App
- Vanilla 자바스크립트를 활용한 버튼 클릭시 이름 변경
- 상태를 사용하지 않고 Vanilla js를 활용해 버튼을 클릭시 이름을 변경할 수 있다.
- 하지만 이 방법은 리액트에서 권장하지 않는 방법이다.
// App.js
import React from 'react'
function App() {
let name = 'winter' // name 변수에 'winter'라는 값을 저장한다.
// changeName() 함수를 정의한다.
function changeName() {
// name의 값이 'winter'이면 'fall'로, 'fall'이면 'winter'로 변경한다.
name = name === 'winter' ? 'fall' : 'winter'
console.log(name) // name의 값을 출력한다.
document.querySelector('h1').innerText = name // h1 태그의 텍스트를 name의 값으로 변경한다.
}
return (
<div className="root">
<h1>{name}</h1>
<button onClick={changeName}>Name Change</button>
</div>
)
}
export default App
- State(상태)를 사용해 버튼 클릭시 이름 변경
- State(상태)를 사용해 버튼을 클릭시 이름을 변경한다.
- State(상태)를 사용하면 컴포넌트가 다시 렌더링된다.
// App.js
// useState를 불러온다.
import React, { useState } from 'react'
function App() {
// name : 상태의 이름, setName : 상태를 변경하는 함수
// useState('winter') : 상태의 초기값
const [name, setName] = useState('winter')
function changeName() {
// 상태를 변경하는 함수(setName)를 사용해 name의 값을 변경한다.
// name의 값이 'winter'이면 'fall'로, 'fall'이면 'winter'로 변경한다.
// 삼항 연산자 : 조건 ? 참일 때 값 : 거짓일 때 값
setName(name === 'winter' ? 'fall' : 'winter')
}
return (
// button을 클릭하면 changeName() 함수를 등록합니다.
<div className="root">
<h1>{name}</h1>
<button onClick={changeName}>Name Change</button>
</div>
)
}
export default App
3. 버튼 클릭시 숫자 변경
- State(상태)를 사용해 버튼을 클릭시 숫자를 변경한다.
- State(상태)를 사용하면 컴포넌트가 다시 렌더링된다.
// App.js
import React, { useState } from 'react' // useState를 불러온다.
function App() {
const [number, setNumber] = useState(0)
function increase() {
setNumber(number + 1)
}
function decrease() {
setNumber(number - 1)
}
return (
<div className="root">
<h1>{number}</h1>
<button onClick={increase}>+</button>
<button onClick={decrease}>-</button>
</div>
)
}
export default App
4. 아이콘 클릭시 아이콘 이미지 변경
import { useState } from 'react'
import { Box } from '@chakra-ui/react'
import switchOn from './assets/images/switch-on.svg'
import switchOff from './assets/images/switch-off.svg'
export default function App() {
const [isToggled, setIsToggled] = useState(false)
return (
<>
<div>
<img
src={isToggled ? switchOn : switchOff}
alt="switch"
onClick={() => {
setIsToggled(!isToggled)
}}
/>
<div>{isToggled ? '켜짐' : '꺼짐'}</div>
</div>
</>
)
}
5. menu 클릭시 active 클래스 변경
import React, { useState } from 'react'
import { AiFillCar } from 'react-icons/ai'
import { LiaUmbrellaBeachSolid } from 'react-icons/lia'
import { PiHouseLineDuotone } from 'react-icons/pi'
import { SiApple } from 'react-icons/si'
import styled from 'styled-components'
const Sort = () => {
const sortArr = [
{ value: '최고의 전망', icon: <SiApple /> },
{ value: '해변 근처', icon: <LiaUmbrellaBeachSolid /> },
{ value: '한옥', icon: <PiHouseLineDuotone /> },
{ value: '농장', icon: <AiFillCar /> },
]
const [selected, setSelected] = useState(0)
return (
<div>
<SortStyled>
{sortArr.map((item, index) => (
<li
key={index}
onClick={() => {
setSelected(index)
}}
className={selected === index ? 'active' : ''}
>
{/* // 클릭 시, selected의 상태를 변경
// selected의 상태가 변경되면, 화면이 다시 렌더링되어 selected === index가 true가 되어 active 클래스가 추가된다. */}
{item.icon}
{item.value}
</li>
))}
</SortStyled>
<div className="tab-contents">
{sortArr.map((item, index) => (
<div key={index} style={{ display: selected === index ? 'block' : 'none' }}>
{item.value}
</div>
))}
</div>
</div>
)
}
const SortStyled = styled.div`
list-style: none;
display: flex;
li {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
width: 100px;
height: 75px;
color: #777;
text-decoration: none;
cursor: pointer;
&:hover {
color: #000;
}
}
svg {
font-size: 30px;
}
.active {
border-bottom: 2px solid #000;
}
`
export default Sort
6. FontAwesome을 사용한 아이콘 변경
// App.js
import React, { useState } from 'react' // useState를 불러온다.
import styled from 'styled-components'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faBars, faTimes } from '@fortawesome/free-solid-svg-icons'
function Menu() {
// isToggled는 상태의 이름, setIsToggled는 상태를 변경하는 함수로 구성한다.
const [isToggled, setIsToggled] = useState(false) // useState(false)는 상태의 초기값이다.
function toggleMenu() {
setIsToggled(!isToggled) // isToggled의 값을 변경한다.
}
return (
// isToggled의 값을 변경한다.
// isToggled의 값을 MenuStyle 컴포넌트에 전달한다.
<MenuStyle isToggled={isToggled}>
<button onClick={toggleMenu}>
// isToggled의 값에 따라 아이콘을 변경하는데 조건을 !isToggled로 설정하는 이유는 // isToggled의 값이
false이면 faBars 아이콘을 출력하고, true이면 faTimes 아이콘을 출력하기 위해서이다.
<FontAwesomeIcon icon={!isToggled ? faBars : faTimes} />
</button>
<ul className="header__menulist">
<li>Mac</li>
<li>iPad</li>
<li>iPhone</li>
<li>Watch</li>
<li>Music</li>
<li>고객지원</li>
</ul>
</MenuStyle>
)
}
const MenuStyle = styled.div`
.header__menulist {
list-style: none;
display: flex;
}
@media screen and (max-width: 768px) {
.header__menulist {
display: ${(props) => (props.isToggled ? 'flex' : 'none')};
flex-direction: column;
width: 100px;
padding: 20px;
background-color: #eee;
}
}
`
function App() {
return <Menu />
}
export default App
7. Input 상태 관리
- State(상태)를 사용해 input의 상태를 관리한다.
// App.js
import React, { useState } from 'react' // useState를 불러온다.
function App() {
// 상태를 정의한다. text는 상태의 이름, setText는 상태를 변경하는 함수이다.
// useState('')은 상태의 초기값이다.
const [text, setText] = useState('')
// input의 값을 변경했을 때 실행되는 함수이다.
// e.target.value : input의 value 속성의 값을 가져온다.
function handleChange(e) {
setText(e.target.value) // setText() 함수를 사용해 text의 값을 변경한다.
// text 상태 값이 변경되면 컴포넌트가 다시 렌더링되기 때문에 text 상태 값이 출력된다.
}
return (
// input의 값을 출력한다.
// input의 값이 변경되면 handleChange() 함수를 실행한다.
<div className="root">
<input type="text" value={text} onChange={handleChange} />
<p>{text}</p>
</div>
)
}
export default App
8. Tabs 구현
import React, { useState } from 'react'
function TabComponent() {
// activeTab : 상태의 이름, setActiveTab : 상태를 변경하는 함수
const [activeTab, setActiveTab] = useState('tab1')
return (
<div>
<ul className="tabs">
<li
role="presentation" // 클릭 가능한 요소로 설정
className={activeTab === 'tab1' ? 'active' : ''} // activeTab의 값이 'tab1'이면 'active' 클래스를 추가한다.
onClick={() => setActiveTab('tab1')} // 클릭 시, activeTab의 값을 'tab1'로 변경한다.
>
tab1
</li>
<li
role="presentation"
className={activeTab === 'tab2' ? 'active' : ''}
onClick={() => setActiveTab('tab2')}
>
tab2
</li>
<li
role="presentation"
className={activeTab === 'tab3' ? 'active' : ''}
onClick={() => setActiveTab('tab3')}
>
tab3
</li>
</ul>
<div className="tab-content">
// activeTab의 값에 따라 화면에 출력되는 내용이 달라진다.
{activeTab === 'tab1' && <div>this is tab1</div>}
{activeTab === 'tab2' && <div>this is tab2</div>}
{activeTab === 'tab3' && <div>this is tab3</div>}
</div>
</div>
)
}
export default TabComponent
- 탭의 내용을 배열로 정의한다.
import React, { useState } from 'react'
function TabComponent() {
const [activeTab, setActiveTab] = useState('tab1')
const tabs = [
{ id: 'tab1', title: 'tab1', content: 'this is tab1' },
{ id: 'tab2', title: 'tab2', content: 'this is tab2' },
{ id: 'tab3', title: 'tab3', content: 'this is tab3' },
]
return (
<div>
<ul className="tabs">
{tabs.map((tab) => (
<li
key={tab.id}
role="presentation"
// activeTab의 값이 tab.id와 같으면 'active' 클래스를 추가한다.
className={activeTab === tab.id ? 'active' : ''}
// 클릭 시, activeTab의 값을 tab.id로 변경한다.
onClick={() => setActiveTab(tab.id)}
>
{tab.title}
</li>
))}
</ul>
<div className="tab-content">
{tabs.map((tab) => (
// activeTab의 값에 따라 화면에 출력되는 내용이 달라진다.
<div key={tab.id} style={{ display: activeTab === tab.id ? 'block' : 'none' }}>
{tab.content}
</div>
))}
</div>
</div>
)
}
export default TabComponent
'Front > React' 카테고리의 다른 글
React Library (0) | 2023.11.06 |
---|---|
Framer Motion - 리액트 라이브러리, 애니메이션 구현 (0) | 2023.11.04 |
이벤트(Event) - React 배우기 (0) | 2023.10.31 |
속성(Props, Properties) - React 배우기 (0) | 2023.10.29 |
React에서 GSAP 사용하기 (0) | 2023.10.27 |