API 연동의 기본
API를 호출하기 위한 axios 라이브러리를 설치한다
- REST API
- URI는 정보의 자원을 표현해야 한다 (리소스명은 동사보다 명사를 사용)
- 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE 등)로 표현한다
Method | 역할 |
POST | POST를 통해 해당 URI를 요청하면 리소스를 생성한다 |
GET | GET를 통해 해당 리소스를 조회한다 |
PUT | PUT를 통해 해당 리소스를 수정한다 |
DELETE | DELETE를 통해 리소스를 삭제한다 |
URI 설계 시 주의사항
- 슬래시 구분자(/)는 계층 관계를 나타내는 데 사용
http://restapi.example.com/houses/apartments
- URI 마지막 문자로 슬래시를 포함하지 않는다
http://restapi.example.com/houses/apartments/ (X)
- 하이픈(-)은 URI 가독성을 높이는데 사용
- 밑줄(_)은 URI에 사용하지 않는다
- URI 경로에는 소문자가 적합하다 (대소문자에 따라 다른 리소스로 인식해서)
- 파일 확장자는 URI에 포함시키지 않는다 (대신 Accept header 사용)
http://restapi.example.com/members/soccer/345/photo.jpg (X)
GET / members/soccer/345/photo HTTP/1.1 Host: restapi.example.com Accept: image/jpg
- HTTP 응답 상태 코드
상태코드 | |
200 | 클라이언트의 요청을 정상적으로 수행함 |
201 | 클라이언트가 어떠한 리소스 생성을 요청, 해당 리소스가 성공적으로 생성됨(POST를 통한 리소스 생성 작업 시) |
상태코드 | |
400 | 클라이언트의 요청이 부적절 할 경우 사용 |
401 | 클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을 때 사용 (로그인 하지 않은 유저가 로그인 했을 때, 요청 가능한 리소스를 요청했을 때) |
403 | 유저 인증상태와 관계 없이 응답하고 싶지 않은 리소스를 클라이언트가 요청했을 때 사용 (403 보다는 400이나 404를 권고, 403은 리소스가 존재한다는 뜻이기 때문) |
405 | 클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을 경우 사용 |
상태코드 | |
301 | 클라이언트가 요청한 리소스에 대한 URI가 변경 되었을 때 사용 (응답 시 Location header에 변경된 URI를 적어 줘야 한다) |
500 | 서버에 문제가 있을 경우 사용 |
- axios의 사용법
import axios from 'axios';
axios.get('/users/1'); //get이 위치한 자리에는 메서드 이름을 소문자로 넣는다
axios.post('/users', {
username: 'Qnd',
name: 'Qnd'
}); // 두번째 파라미터에 등록하고자 하는 정보를 넣을 수 있다
- useState와 useEffect로 데이터 로딩하기
총 3가지 상태 관리 필요
- 요청의 결과
- 로딩 상태
- 에러
// Users.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const Users = () => {
const [users, setUsers] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => { //첫번째 파라미터로 등록하는 함수에는 async 사용 불가
const fetchUsers = async () => { //함수 내부에서 async라는 새로운 함수 선언
try {
// 요청이 시작 할 때에는 error 와 users 를 초기화하고
setError(null);
setUsers(null);
// loading 상태를 true 로 바꿉니다.
setLoading(true);
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
setUsers(response.data); // 데이터는 response.data 안에 들어있습니다.
} catch (e) {
setError(e);
}
setLoading(false);
};
fetchUsers();
}, []);
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return null;
return (
<ul>
{users.map(user => (
<li key={user.id}>
{user.username} ({user.name})
</li>
))}
</ul>
);
}
export default Users;
- useEffect에 첫 번째 파라미터로 등록하는 함수에는 async 사용 불가 (useEffect가 반환하는 것이 cleanup 함수 또는 undefined여야하는데 비동기 함수는 Promise를 반환하기 때문)
useEffect(async () => {
// 비동기 함수로 작성한 경우
}, []);
useEffect(() => {
// useEffect 내부에서 비동기 함수를 선언하고 호출
const fetchUsers = async () => {
// 비동기 작업 수행
};
fetchUsers();
}, []);
- 로딩 상태가 활성화 됐을 땐 로딩중.. 문구가 보여짐
- users의 값이 없을 때에는 null이 보여짐
- 마지막에는 users 배열 렌더링
주소를 이상하게 바꾸면
- 버튼으로 API 재요청하기
버튼 클릭으로 API를 재요청하려면 fetchUsers 함수가 useEffect 외부에서도 호출될 수 있어야 한다
=>fetchUsers 함수를 바깥으로 꺼내주기
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const Users=()=>{
const [users, setUsers] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchUsers = async () => {
try {
// 요청이 시작 할 때에는 error 와 users 를 초기화하고
setError(null);
setUsers(null);
// loading 상태를 true 로 바꿉니다.
setLoading(true);
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
setUsers(response.data); // 데이터는 response.data 안에 들어있습니다.
} catch (e) {
setError(e);
}
setLoading(false);
};
//컴포넌트가 처음 렌더링될 때 fetchUsers 호출
useEffect(() => {
fetchUsers();
}, []);
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return null;
return (
<>
<ul>
{users.map(user => (
<li key={user.id}>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={fetchUsers}>다시 불러오기</button>
</>
);
}
export default Users;
useReducer로 요청 상태 관리하기
LOADING, SUCCESS, ERROR 액션에 따라 다르게 처리
import React, { useEffect, useReducer } from 'react';
import axios from 'axios';
const reducer = (state, action) => {
switch (action.type) {
case 'LOADING':
return {
loading: true,
data: null,
error: null
};
case 'SUCCESS':
return {
loading: false,
data: action.data,
error: null
};
case 'ERROR':
return {
loading: false,
data: null,
error: action.error
};
default:
throw new Error(`Unhandled action type: ${action.type}`);
}
}
const Users = () => {
const [state, dispatch] = useReducer(reducer, {
loading: false,
data: null,
error: null
});
const fetchUsers = async () => {
dispatch({ type: 'LOADING' });
try {
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
dispatch({ type: 'SUCCESS', data: response.data });
} catch (e) {
dispatch({ type: 'ERROR', error: e });
}
};
useEffect(() => {
fetchUsers();
}, []);
const { loading, data: users, error } = state; // state.data 를 users 키워드로 조회
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return null;
return (
<>
<ul>
{users.map(user => (
<li key={user.id}>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={fetchUsers}>다시 불러오기</button>
</>
);
}
export default Users;
장점
- useState의 setState 함수를 여러번 사용하지 않아도 된다
- 다른 곳에서도 쉽게 재사용 가능
useAsync 커스텀 Hook 만들어서 사용하기
커스텀 Hook (리액트의 상태 관리나 로직을 쉽게 재사용하기 위해 만든 함수 = 레시피) 을 만들면 요청 상태 관리 로직을 쉽게 재사용 할 수 있다
//useAsync.js
import { useReducer, useEffect } from 'react';
const reducer = (state, action) => {
switch (action.type) {
case 'LOADING':
return {
loading: true,
data: null,
error: null
};
case 'SUCCESS':
return {
loading: false,
data: action.data,
error: null
};
case 'ERROR':
return {
loading: false,
data: null,
error: action.error
};
default:
throw new Error(`Unhandled action type: ${action.type}`);
}
}
const useAsync = (callback, deps = []) => { // callback은 API 요청을 시작하는 함수, deps는 해당 함수 안에서 사용하는 useEffect의 deps로 설정
const [state, dispatch] = useReducer(reducer, {
loading: false,
data: null,
error: false
});
const fetchData = async () => {
dispatch({ type: 'LOADING' });
try {
const data = await callback();
dispatch({ type: 'SUCCESS', data });
} catch (e) {
dispatch({ type: 'ERROR', error: e });
}
};
useEffect(() => {
fetchData();
// eslint 설정을 다음 줄에서만 비활성화
// eslint-disable-next-line
}, deps);
return [state, fetchData]; // fetchData 함수를 반환해 나중에 데이터를 쉽게 리로딩 해줄 수 있다
}
export default useAsync;
deps 값은 나중에 사용할 비동기 함수에서 파라미터가 필요하고, 그 파라미터가 바뀔 때 새로운 데이터를 불러오고 싶은 경우 활용할 수 있다 (현재는 불필요, 기본값은 [])
//Users.js
import React from 'react';
import axios from 'axios';
import useAsync from './useAsync';
const getUsers = async() => {
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
return response.data;
}
const Users = () => {
const [state, refetch] = useAsync(getUsers, []);
const { loading, data: users, error } = state; // state.data 를 users 키워드로 조회
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return null;
return (
<>
<ul>
{users.map(user => (
<li key={user.id}>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={refetch}>다시 불러오기</button>
</>
);
}
export default Users;
- 데이터 나중에 불러오기 (특정 버튼을 눌렀을 때만 API 요청)
// useAsync.js
import { useReducer, useEffect } from 'react';
const reducer = (state, action) => {
switch (action.type) {
case 'LOADING':
return {
loading: true,
data: null,
error: null
};
case 'SUCCESS':
return {
loading: false,
data: action.data,
error: null
};
case 'ERROR':
return {
loading: false,
data: null,
error: action.error
};
default:
throw new Error(`Unhandled action type: ${action.type}`);
}
}
const useAsync = (callback, deps = [], skip = false) => { //skip의 값이 true면 useEffect에서 아무런 작업도 하지 않도록 설정
const [state, dispatch] = useReducer(reducer, {
loading: false,
data: null,
error: false
});
const fetchData = async () => {
dispatch({ type: 'LOADING' });
try {
const data = await callback();
dispatch({ type: 'SUCCESS', data });
} catch (e) {
dispatch({ type: 'ERROR', error: e });
}
};
useEffect(() => {
if (skip) return;
fetchData();
// eslint 설정을 다음 줄에서만 비활성화
// eslint-disable-next-line
}, deps);
return [state, fetchData];
}
export default useAsync;
// Users.js
import React from 'react';
import axios from 'axios';
import useAsync from './useAsync';
const getUsers = async () => {
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
return response.data;
}
const Users = () => {
const [state, refetch] = useAsync(getUsers, [], true);
const { loading, data: users, error } = state; // state.data 를 users 키워드로 조회
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return <button onClick={refetch}>불러오기</button>;
return (
<>
<ul>
{users.map(user => (
<li key={user.id}>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={refetch}>다시 불러오기</button>
</>
);
}
export default Users;
- API 에 파라미터가 필요한 경우
User 컴포넌트 만들고 id 값을 props로 받아 와서
https://jsonplaceholder.typicode.com/users/1 이렇게 맨 뒤에 id를 넣어 API를 요청하자
//User.js
import React from 'react';
import axios from 'axios';
import useAsync from './useAsync';
const getUser = async (id) => {
const response = await axios.get(
`https://jsonplaceholder.typicode.com/users/${id}`
);
return response.data;
}
const User = ({ id }) => {
const [state] = useAsync(() => getUser(id), [id]); //id 가 바뀔 때마다 재호출
const { loading, data: user, error } = state;
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!user) return null;
return (
<div>
<h2>{user.username}</h2>
<p>
<b>Email:</b> {user.email}
</p>
</div>
);
}
export default User;
//Users.js
import React, { useState } from 'react';
import axios from 'axios';
import useAsync from './useAsync';
import User from './User';
const getUsers = async () => {
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
return response.data;
}
const Users = () => {
const [userId, setUserId] = useState(null); //초깃값은 null, 클릭한 사용자의 id를 userId 값으로 설정
const [state, refetch] = useAsync(getUsers, [], true);
const { loading, data: users, error } = state; // state.data 를 users 키워드로 조회
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return <button onClick={refetch}>불러오기</button>;
return (
<>
<ul>
{users.map(user => (
<li
key={user.id}
onClick={() => setUserId(user.id)}
style={{ cursor: 'pointer' }}
>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={refetch}>다시 불러오기</button>
{userId && <User id={userId} />}
</>
);
}
export default Users;
react-async 로 요청 상태 관리하기
react-async : useAsync와 비슷한 함수가 들어있는 라이브러리, 매번 직접 요청 상태 관리를 위한 커스텀 Hook을 만들기 귀찮을 때 사용할 수 있다. 커스텀 Hook은 결과물을 배열로 반환하지만 이 Hook은 객체 형태로 반환한다
import { useAsync } from "react-async"
const loadCustomer = async ({ customerId }, { signal }) => {
const res = await fetch(`/api/customers/${customerId}`, { signal })
if (!res.ok) throw new Error(res)
return res.json()
}
const MyComponent = () => {
const { data, error, isLoading } = useAsync({ promiseFn: loadCustomer, customerId: 1 })
if (isLoading) return "Loading..."
if (error) return `Something went wrong: ${error.message}`
if (data)
return (
<div>
<strong>Loaded some data:</strong>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
)
return null
}
useAsync를 사용 할 때 파라미터로 넣은 옵션 객체에는 호출 할 함수 promiseFn, 파라미터도 필드 이름과 함께 customerId 넣어줘야 한다
- User 컴포넌트를 react-async의 useAsync로 전환해보자
//User.js
import React from 'react';
import axios from 'axios';
import { useAsync } from 'react-async';
const getUser = async({ id }) => { //프로미스를 반환하는 함수의 파라미터를 객체 형태로 작성 (id 값을 따로 받아와서 사용하기 위해)
const response = await axios.get(
`https://jsonplaceholder.typicode.com/users/${id}`
);
return response.data;
}
const User = ({ id }) => {
const { data: user, error, isLoading } = useAsync({
promiseFn: getUser,
id,
watch: id //watch 값에 특정 값을 넣어주면 그 값이 바뀔 때마다 getUser를 다시 호출해준다
});
if (isLoading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!user) return null;
return (
<div>
<h2>{user.username}</h2>
<p>
<b>Email:</b> {user.email}
</p>
</div>
);
}
export default User;
- Users 컴포넌트를 react-async의 useAsync로 전환하기
//Users.js
import React, { useState } from 'react';
import axios from 'axios';
import { useAsync } from 'react-async';
import User from './User';
const getUsers = async() => {
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
return response.data;
}
const Users = () => {
const [userId, setUserId] = useState(null);
const { data: users, error, isLoading, reload } = useAsync({
promiseFn: getUsers
});
if (isLoading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return <button onClick={reload}>불러오기</button>;
return (
<>
<ul>
{users.map(user => (
<li
key={user.id}
onClick={() => setUserId(user.id)}
style={{ cursor: 'pointer' }}
>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={reload}>다시 불러오기</button>
{userId && <User id={userId} />}
</>
);
}
export default Users;
컴포넌트를 렌더링하는 시점부터 데이터를 불러오게 된다
렌더링하는 시점에 API 호출 - promiseFn, reload 사용
사용자의 특정 인터랙션에 따라 API 호출 - deferFn, run 사용
Context 와 함께 사용하기
특정 데이터들은 다양한 컴포넌트에서 필요하게 될 때는 (현재 로그인된 사용자의 정보, 설정 등) Context 를 사용하면 개발이 편해진다
// UsersContext.js
import React, { createContext, useReducer, useContext } from 'react';
// UsersContext 에서 사용 할 기본 상태
const initialState = {
users: {
loading: false,
data: null,
error: null
},
user: {
loading: false,
data: null,
error: null
}
};
// 로딩중일 때 바뀔 상태 객체
const loadingState = {
loading: true,
data: null,
error: null
};
// 성공했을 때의 상태 만들어주는 함수
const success = data => ({
loading: false,
data,
error: null
});
// 실패했을 때의 상태 만들어주는 함수
const error = error => ({
loading: false,
data: null,
error: error
});
// 위에서 만든 객체 / 유틸 함수들을 사용하여 리듀서 작성
const usersReducer = (state, action) => {
switch (action.type) {
case 'GET_USERS':
return {
...state,
users: loadingState
};
case 'GET_USERS_SUCCESS':
return {
...state,
users: success(action.data)
};
case 'GET_USERS_ERROR':
return {
...state,
users: error(action.error)
};
case 'GET_USER':
return {
...state,
user: loadingState
};
case 'GET_USER_SUCCESS':
return {
...state,
user: success(action.data)
};
case 'GET_USER_ERROR':
return {
...state,
user: error(action.error)
};
default:
throw new Error(`Unhanded action type: ${action.type}`);
}
}
// State 용 Context 와 Dispatch 용 Context 따로 만들어주기
const UsersStateContext = createContext(null);
const UsersDispatchContext = createContext(null);
// 위에서 선언한 두가지 Context 들의 Provider 로 감싸주는 컴포넌트
export function UsersProvider({ children }) {
const [state, dispatch] = useReducer(usersReducer, initialState);
return (
<UsersStateContext.Provider value={state}>
<UsersDispatchContext.Provider value={dispatch}>
{children}
</UsersDispatchContext.Provider>
</UsersStateContext.Provider>
);
}
// State 를 쉽게 조회 할 수 있게 해주는 커스텀 Hook
export function useUsersState() {
const state = useContext(UsersStateContext);
if (!state) {
throw new Error('Cannot find UsersProvider');
}
return state;
}
// Dispatch 를 쉽게 사용 할 수 있게 해주는 커스텀 Hook
export function useUsersDispatch() {
const dispatch = useContext(UsersDispatchContext);
if (!dispatch) {
throw new Error('Cannot find UsersProvider');
}
return dispatch;
}
id를 가지고 특정 사용자의 정보를 가져오는 API를 호출하고 싶을 땐 (요청이 시작 했을 때 액션을 디스패치, 성공하거나 실패했을 때 또 다시 디스패치)
dispatch({ type: 'GET_USER' });
try {
const response = await getUser();
dispatch({ type: 'GET_USER_SUCCESS', data: response.data });
} catch (e) {
dispatch({ type: 'GET_USER_ERROR', error: e });
}
- 만든 Context 사용하기
//Users.js
import React, { useState } from 'react';
import { useUsersState, useUsersDispatch, getUsers } from './UsersContext';
import User from './User';
const Users = () => {
const [userId, setUserId] = useState(null);
const state = useUsersState();
const dispatch = useUsersDispatch();
const { data: users, loading, error } = state.users;
const fetchData = () => {
getUsers(dispatch);
};
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return <button onClick={fetchData}>불러오기</button>;
return (
<>
<ul>
{users.map(user => (
<li
key={user.id}
onClick={() => setUserId(user.id)}
style={{ cursor: 'pointer' }}
>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={fetchData}>다시 불러오기</button>
{userId && <User id={userId} />}
</>
);
}
export default Users;
useUsersState() 와 useUsersDispatch() 로 state 와 dispatch 를 가져오고, 요청을 시작 할 때에는 getUsers() 함수 안에 dispatch 를 넣어서 호출해준다
// User.js
import React, { useEffect } from 'react';
import { useUsersState, useUsersDispatch, getUser } from './UsersContext';
const User = ({ id }) => {
const state = useUsersState();
const dispatch = useUsersDispatch();
useEffect(() => { // id 값이 바뀔 때마다 getUser() 호출
getUser(dispatch, id);
}, [dispatch, id]);
const { data: user, loading, error } = state.user;
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!user) return null;
return (
<div>
<h2>{user.username}</h2>
<p>
<b>Email:</b> {user.email}
</p>
</div>
);
}
export default User;
getUser() 함수를 호출 할 때에는 두번째 파라미터에 현재 props 로 받아온 id 값을 넣어준다
추가자료
- 라우팅
웹 애플리케이션에서의 라우팅 - 사용자가 요청한 URL에 따라 알맞는 페이지를 보여주는 것
리액트에서 라우트 시스템을 구축하기 위해 리액트 라우터 또는 Next.js를 사용할 수 있다
- 싱글 페이지 애플리케이션
한 개의 페이지로 이루어진 애플리케이션 (html을 한번만 받아와서 웹 애플리케이션을 실행시킨 후에 그 이후에는 필요한 데이터만 받아와서 화면에 업데이트 해주는 것)
=> 사용자가 경험하기에는 여러 페이지가 존재하는 것처럼 느낄 수 있다
- 리액트 라우터 사용하기
Route 컴포넌트를 통해 라우트 설정을 해주어야 한다
<Route path="주소규칙" element={보여 줄 컴포넌트 JSX} />
Link 컴포넌트를 사용해 다른 페이지로 이동하는 링크를 보여주자
<Link to="경로">링크 이름</Link>
a 태그를 사용하면 페이지를 새로 불러오게 되지만 Link 컴포넌트에는 페이지를 새로 불러오는 것을 막고 History API를 통해 브라우저 주소의 경로만 바꾸는 기능이 내장되어 있다!
- URL 파라미터와 쿼리스트링
- URL 파라미터 : 주소 경로에 유동적인 값을 넣는 형태 / ID 또는 이름을 사용해 특정 데이터를 조회할 때 사용 (ex. /profile/wink)
- 쿼리스트링 : 주소의 뒷부분에 ? 이후에 key=value 로 값을 정의하며 & 로 구분하는 형태 / 키워드 검색, 페이지네이션, 정렬 방식 등 데이터 조회에 필요한 옵션을 전달할 때 사용 (ex. /articles?**page=1&keyword=react)
URL 파라미터를 사용해보자
쿼리스트링을 사용해보자
URL 파라미터와 다르게 Route 컴포넌트를 사용할 때 별도로 설정해야하는 것이 없다
useLocation Hook이 반환하는 객체에 있는 값들
- pathname: 현재 주소의 경로 (쿼리스트링 제외)
- search: 맨 앞의 ? 문자 포함한 쿼리스트링 값
- hash: 주소의 # 문자열 뒤의 값 (주로 History API 가 지원되지 않는 구형 브라우저에서 클라이언트 라우팅을 사용할 때 쓰는 해시 라우터에서 사용합니다.)
- state: 페이지로 이동할때 임의로 넣을 수 있는 상태 값
- key: location 객체의 고유 값, 초기에는 default 이며 페이지가 변경될때마다 고유의 값이 생성됨
?detail=true&mode=1에서 key와 value를 파싱하는 작업을 해야한다
useSearchParams로 쿼리스트링을 쉽게 파싱해보자
- useSearchParams 는 배열 타입의 값을 반환한다
- 첫번째 원소는 쿼리파라미터를 조회하거나 수정하는 메서드들이 담긴 객체를 반환한다
- get 메서드를 통해 특정 쿼리파라미터를 조회할 수 있고, set 메서드를 통해 특정 쿼리파라미터를 업데이트 할 수 있다. 쿼리파라미터가 존재하지 않는다면 null 로 조회된다
- 두번째 원소는 쿼리파라미터를 객체형태로 업데이트할 수 있는 함수를 반환한다
* 쿼리파라미터를 조회할 때 값은 무조건 문자열 타입이다!
- 중첩된 라우트
//App.js
import { Route, Routes } from 'react-router-dom';
import About from './pages/About';
import Article from './pages/Article';
import Articles from './pages/Articles';
import Home from './pages/Home';
import Profile from './pages/Profile';
const App = () => {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/profiles/:username" element={<Profile />} />
<Route path="/articles" element={<Articles />}>
<Route path=":id" element={<Article />} />
</Route>
</Routes>
);
};
export default App;
// Articles.js
import { Link, Outlet } from 'react-router-dom';
const Articles = () => {
return (
<div>
<Outlet />
<ul>
<li>
<Link to="/articles/1">게시글 1</Link>
</li>
<li>
<Link to="/articles/2">게시글 2</Link>
</li>
<li>
<Link to="/articles/3">게시글 3</Link>
</li>
</ul>
</div>
);
};
export default Articles;
Outlet 컴포넌트가 사용된 자리에 중첩된 라우트가 보여지게 된다
- 리액트 라우터 부가기능
1. useNavigate - Link 컴포넌트를 사용하지 않고 다른 페이지로 이동을 해야 하는 상황에 사용하는 Hook
2. NavLink - 링크에서 사용하는 경로가 현재 라우트의 경로와 일치하는 경우 특정 스타일 또는 CSS 클래스를 적용하는 컴포넌트 (style또는 className을 설정할 때 { isActive: boolean } 을 파라미터로 전달받는 함수 타입의 값을 전달한다)
3. Navigate 컴포넌트 - 컴포넌트를 화면에 보여주는 순간 다른 페이지로 이동 하고 싶을 때 사용하는 컴포넌트
'WINK-(Web & App) > React.js 스터디' 카테고리의 다른 글
[2024 여름방학 React.js 스터디] #6주차 이가인 (0) | 2024.08.16 |
---|---|
[2024 여름방학 React.js 스터디] 정채은 #6주차 (0) | 2024.08.16 |
[2024 여름방학 React.js 스터디] 백채린 #6주차 (0) | 2024.08.16 |
[2024 여름방학 React.js 스터디] 정채은 #5주차 (0) | 2024.08.09 |
[2024 여름방학 React.js 스터디] 이가인 #5주차 (0) | 2024.08.09 |