//[ Counter.js ]
//초기값
const initialState = {
number: 0,
};
// const [number, setNumber] = usestate(0)과 같은 것
export const PLUS_ONE = "counter/PLUS_ONE";
export const MINUS_ONE = "counter/MINUS_ONE";
// 리듀서 = state에 변화를 일으키는 함수
// 변화 : state를 action의 type에 따라 변경하는 함수
// input : state와 action
const counter = (state = initialState, action) => {
switch (action.type) {
case PLUS_ONE:
return { number: state.number + 1 };
case MINUS_ONE:
return { number: state.number - 1 };
default:
return state;
}
};
export default counter;
//[ App.jsx ]
import logo from "./logo.svg";
import "./App.css";
import { useDispatch, useSelector } from "react-redux"; //
import { PLUS_ONE, MINUS_ONE } from "./redux/modules/counter";
function App() {
const counter = useSelector((state) => {
return state.counter;
});
const dispatch = useDispatch();
return (
<div className="App">
<div>현재 카운트 : {counter.number}</div>
<button
onClick={() => {
dispatch({
type: PLUS_ONE,
});
}}
>
+
</button>
<button
onClick={() => {
dispatch({
type: MINUS_ONE,
});
}}
>
-
</button>
</div>
);
}
export default App;
1) 이전에 뭘 했고 지금은 뭘 할 것인가?
+1과 -1버튼을 각각 누르면 증가되거나 감소하는 카운터를 만들었고
만약 사용자가 어떤 input에 5를 입력하고 버튼 누르면 5 증가하고 10을 입력하면 10이 증가하는 프로그램이 되도록 하는 것
2) Payload란 무엇인가?
// payload가 추가된 액션객체
{type: "ADD_NUMBER", payload: 10}
// type뿐만 아니라 payload라는 key와 value를 같이 담는다.
1) 사용자가 입력한 값을 받을 input 구현:
// src/App.js
import React from "react";
import { useState } from "react";
const App = () => {
const [number, setNumber] = useState(0);
const onChangeHandler = (event) => {
const { value } = event.target;
setNumber(+value);
};
console.log(number);
return (
<div>
<input type="number" onChange={onChangeHandler} />
<button>더하기</button>
<button>빼기</button>
</div>
);
};
export default App;
☞ Input과 더하기/빼기 버튼을 구현하고, 입력값을 상태로 관리함.
2) Counter.js 모듈 작성: Action Creator:
// src/redux/modules/counter.js
const ADD_NUMBER = "ADD_NUMBER";
export const addNumber = (payload) => ({
type: ADD_NUMBER,
payload,
});
☞ Action Value와 Action Creator를 작성하고, payload를 받아와 액션 객체를 생성함.
3) Counter.js 모듈 작성 : Initial State, Reducer, 내보내기:
// src/redux/modules/counter.js
const initialState = {
number: 0,
};
const counter = (state = initialState, action) => {
switch (action.type) {
case ADD_NUMBER:
return {
number: state.number + action.payload,
};
default:
return state;
}
};
export default counter;
☞ Initial State와 Reducer의 기본 형태를 작성하고, 더하기 기능의 로직을 추가함.
4) 구현된 기능 테스트
// src/App.js
import React from "react";
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { addNumber } from "./redux/modules/counter";
const App = () => {
const dispatch = useDispatch();
const [number, setNumber] = useState(0);
const globalNumber = useSelector((state) => state.counter.number);
const onChangeHandler = (event) => {
const { value } = event.target;
setNumber(+value);
};
const onClickAddNumberHandler = () => {
dispatch(addNumber(number));
};
return (
<div>
<div>{globalNumber}</div>
<input type="number" onChange={onChangeHandler} />
<button onClick={onClickAddNumberHandler}>더하기</button>
<button>빼기</button>
</div>
);
};
export default App;
☞ useSelector로 Store의 값을 조회하여 화면에 렌더링하고, useDispatch를 사용하여 Action Creator를 호출하여 기능을 테스트함
2 . react-router-dom 사용하기
1. 페이지 컴포넌트 생성
2. Router.js 생성 및 route 설정 코드 작성
3. App.js에서 Router.js import 및 적용
4. 페이지 이동 테스트
Router.js 설정:
// src/shared/Router.js
import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from '../pages/Home';
import About from '../pages/About';
import Contact from '../pages/Contact';
import Works from '../pages/Works';
import Layout from './Layout';
const Router = () => {
return (
<BrowserRouter>
<Layout>
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<About />} />
<Route path="contact" element={<Contact />} />
<Route path="works" element={<Works />} />
</Routes>
</Layout>
</BrowserRouter>
);
};
export default Router;
☞ BrowserRouter, Route, Routes 등을 이용하여 페이지 간 이동을 설정
// src/pages/Home.js
import React from 'react';
import { useNavigate } from 'react-router-dom';
const Home = () => {
const navigate = useNavigate();
return (
<button
onClick={() => {
navigate('/works');
}}
>
Works 페이지로 이동
</button>
);
};
export default Home;
☞ 다른 페이지로 이동할 때 사용하는 Hook.
☞ 버튼 클릭 등의 이벤트 핸들러에서 useNavigate를 이용해 페이지 이동 구현
// src/pages/Works.js
import React from 'react';
import { useLocation, Link } from 'react-router-dom';
const Works = () => {
const location = useLocation();
return (
<div>
<div>{`현재 페이지: ${location.pathname.slice(1)}`}</div>
<Link to="/contact">Contact 페이지로 이동</Link>
</div>
);
};
export default Works;
☞ 현재 페이지에 대한 정보를 얻을 때 사용하는 Hook.
☞ 현재 URL과 관련된 정보를 객체로 제공.
// src/pages/Works.js
import React from 'react';
import { useLocation, Link } from 'react-router-dom';
const Works = () => {
const location = useLocation();
return (
<div>
<div>{`현재 페이지: ${location.pathname.slice(1)}`}</div>
<Link to="/contact">Contact 페이지로 이동</Link>
</div>
);
};
export default Works;
☞ a 태그의 역할을 하는 컴포넌트.
☞ 페이지 이동 시 새로고침을 방지하고, SPA의 장점을 유지.
동기적 프로그래밍: 코드는 순차적으로 실행되며, 앞선 코드가 완료되어야 다음 코드가 실행됨.
비동기적 프로그래밍: 코드의 실행이 완료 여부와 관계없이 다음 코드로 즉시 넘어감. 대표적으로 setTimeout, 이벤트 처리, 서버 통신과 관련된 비동기 코드가 있음.
###콜백지옥 (Callback Hell)
콜백지옥이 발생 하면?
비동기 코드 중첩이 깊어져 들여쓰기가 많아지고, 코드가 가독성이 떨어지고 수정이 어려워짐
해결책: ES6에서 소개된 Promise 객체를 사용하여 비동기 코드를 더 효율적으로 관리.
1) 상태:
대기 (pending): 작업이 아직 성공 또는 실패하지 않은 상태.
이행 (fulfilled): 작업이 성공적으로 완료된 상태.
거부 (rejected): 작업이 실패한 상태.
2) 핸들링 방법:
then ~ catch: Promise 객체의 상태에 따라 적절한 처리를 수행.
async / await: Promise 객체를 더 간결하게 다루는 방법으로, 비동기 함수 내에서 동작.
3) then ~ catch 활용:
axios.get('http://api.naver.com/weather/today')
.then(response => {
console.log('정상처리 되었습니다: ' + response);
})
.catch(error => {
console.log('오류가 발생하였습니다: ' + error);
})
.finally(() => {
console.log('항상 실행되는 부분입니다!');
});
4) async / await 활용:
const getWeather = async () => {
try {
const response = await axios.get('http://api.naver.com/weather/today');
console.log('정상처리 되었습니다: ' + response);
} catch (error) {
console.log('오류가 발생하였습니다: ' + error);
}
}
예시: GET /users/3/profile은 "user 중에서 ID가 3인 사용자의 프로필을 요청"하는 것으로 자원과 행위를 명확히 표현함
REST API 규칙 및 예시
1) 명명 규칙:
2) 예시
http://example.com/posts (O)
http://example.com/post (X)
http://example.com/post/assets/example (O)
RESTful한 API는 위의 규칙을 따라 명확하고 사용하기 쉬운 API를 의미함
장점은 이해하기 쉽고 일관된 디자인으로 다양한 클라이언트가 활용할 수 있음
REST 개발 시, 데이터를 가져올 때 주로 사용되는 두 가지 방법
경로 자체에 변수를 사용하여 리소스를 특정하는 방법
예시: /users/10
특히, 전체 데이터 또는 특정 데이터를 식별할 때 사용
URI에 변수를 추가하여 데이터를 정렬하거나 필터링하는 방법
예시: /users?user_id=10
주로 데이터를 정렬하거나 필터링할 때 사용
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [
{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": [
"Radiation resistance",
"Turning tiny",
"Radiation blast"
]
},
]
}
console.log(JSON.stringify({ x: 5, y: 6 })); // "{"x":5,"y":6}"
const json = '{"result":true, "count":42}';
const obj = JSON.parse(json);
console.log(obj.count); // 42
import logo from "./logo.svg";
import "./App.css";
import { useEffect, useState } from "react";
function App() {
const [data, setData] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((response) => response.json())
.then((json) => {
setData([...json]);
return console.log(json);
});
}, []);
return (
<div className="App">
<h3>jsonplaceholder Data</h3>
{data.map(function (item) {
return (
<div>
<ul>
<li>{item.userID}</li>
<li>{item.id}</li>
<li>{item.title}</li>
<li>{item.body}</li>
</ul>
</div>
);
})}
</div>
);
}
export default App;
오늘의 한줄평 : 리덕스가 조금 어려웠다. 와 복습도 열심히 해야겠다...