useContext
- React에서 제공하는 Hook 중 하나로 컴포넌트 간에 상태를 공유하기 위해 사용됨.
- 중간 컴포넌트를 건너뛰고 상위 컴포넌트에서 하위 컴포넌트로 직접 데이터를 전달할 수 있다.
- 주로 상위 컴포넌트에서 상태를 관리하므로 상태 업데이트의 범위가 제한적.
- useContext는 작은 규모의 애플리케이션에서 상태 관리를 수행하기에 적합하다.
useRef 사용
import React, { useContext, createContext } from 'react';
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const theme = 'light';
return (
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme === 'light' ? '#ffffff' : '#000000', color: theme === 'light' ? '#000000' : '#ffffff' }}>
{theme === 'light' ? 'Light Theme' : 'Dark Theme'}
</button>
);
}
function App() {
return (
<ThemeProvider>
<ThemedButton />
</ThemeProvider>
);
}
Redux
- 전역 상태 관리를 제공하여 여러 컴포넌트 간에 데이터를 효율적으로 공유할 수 있도록 해준다
- Redux는 상태의 변화를 관리하고, 상태가 변화할 때마다 컴포넌트들에게 적절한 업데이트를 제공하기 위해 액션(Action)과 리듀서(Reducer) 등의 개념을 사용한다.
- 단일 저장소(store)에 상태를 저장하고 관리한다.
Action
- Action은 Redux에서 상태 변화를 발생시키는 일종의 객체. Action 객체에는 상태를 어떻게 변경할지에 대한 정보가 담겨 있다.
- Action은 애플리케이션에서 발생하는 어떤 사건이나 이벤트를 설명하는 type과, 필요에 따라 추가적인 payload가 포함된다.
Reducer
- Reducer는 Redux에서 상태를 변경하는 순수 함수이다. 이전 state와 Action을 받아서 새로운 상태를 반환.
- Reducer는 Action의 타입에 따라 상태를 어떻게 업데이트할지를 결정한다.
- 기존의 state를 직접 수정하지 않고, 불변성을 유지해야 한다.
const initialState = {
users: [],
isFormSubmitted: false,
}
const userReducer = (state = initialState, action) => {
switch (action.type) {
case 'ADD_USER':
return {
...state,
users: [...state.users, action.payload],
}
case 'SUBMIT_FORM':
return {
...state,
isFormSubmitted: true,
}
default:
return state
}
}
export default userReducer
store
- 스토어는 Redux에서 state를 저장하는 객체. 애플리케이션의 전역 상태를 관리하고, Action에 따라 상태를 업데이트하며, Reducer를 호출하여 새로운 상태를 계산.
- Redux에서는 단 하나의 스토어만 사용.
- 애플리케이션의 현재 state를 조회할 수 있다.
- dispatch 메서드를 사용하여 Action을 전달하고, Reducer를 호출하여 상태를 업데이트.
- subscribe 메서드를 사용하여 상태가 변화할 때마다 등록된 콜백 함수를 호출.
- store는 보통 Redux의 createStore 함수를 사용하여 생성.
import {createStore} from 'redux'
import {Provider} from 'react-redux'
import userReducer from './reducers'
const store = createStore(userReducer)
Provider
- Provider 컴포넌트를 사용하여 React 애플리케이션에 store를 제공합니다. 이를 통해 하위 컴포넌트들이 store에 접근할 수 있게 된다.
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Connect
- react-redux의
connect
함수를 사용하여 React 컴포넌트를 store와 연결. 이를 통해 컴포넌트는 Redux 상태를 프로퍼티로 매핑하고, 액션을 디스패치하여 상태를 변경할 수 있다.
import React from 'react';
import { connect } from 'react-redux';
import { login } from './actions';
const LoginComponent = ({ user, login }) => {
return (
<div>
<h2>Hello, {user.username}</h2>
<button onClick={() => login('user123', 'password123')}>Login</button>
</div>
);
};
const mapStateToProps = (state) => {
return {
user: state.user
};
};
const mapDispatchToProps = {
login
};
export default connect(mapStateToProps, mapDispatchToProps)(LoginComponent)
Redux에서의 데이터 흐름 정리
1. 컴포넌트에서 Aciton 발생
2. Aciton은 Reducer로 전달
3. Reducer는 Acitond의 타입을 기반으로 state를 업데이트
4. 변경된 state는 store에 저장
5. store의 state가 변화하면, 해당 변화를 감지하고 있는 컴포넌트들이 자동으로 리렌더링
- Redux Toolkit을 통해 Redux의 상태 관리를 더 쉽고 간편하게 만들어준다.
- 내부적으로 immer 라이브러리를 사용하여 불변성을 유지한다. 이를 통해 상태를 더 직관적이고 간결하게 업데이트 가능.
- 몇 가지 유용한 미들웨어를 기본으로 내장. 비동기 작업 처리를 위한
createAsyncThunk
와 같은 유틸리티 함수들을 사용하여 비동기 작업을 간단하게 처리 가능.
- 개발자 도구를 사용하여 액션과 상태의 변화를 실시간으로 모니터링하고 디버깅할 수 있다.
- 일반적인 Redux 패턴을 사용하는데 필요한 기본적인 설정을 간소화한다.
createSlice
reateSlice
힘수를 사용하면 액션과 리듀서를 한 번에 생성할 수 있다.
import { createSlice, current } from "@reduxjs/toolkit";
import informCardList from "../pages/Inform/InformSection/db/informCardImg.json";
const initialState = {
informCardLists: informCardList,
};
const informCardListSlice = createSlice({
name: "informCardList",
initialState: initialState,
reducers: {
setInformCardList(state, action) {
state.informCardLists = action.payload;
},
},
});
export const { setInformCardList } = informCardListSlice.actions;
export default informCardListSlice.reducer;
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setInformCardList } from "../../services/InformCardListSlice";
export default function BookMark() {
const { informCardLists } = useSelector((state) => state.informCardLists);
let temp = JSON.parse(JSON.stringify(informCardLists))
return (
<>
<section className="inform_card_detail">
<>
{temp
.filter((x) => x.bookmark === true)
.map((x) => {
return (
<BookmarkCardContaner
key={x.id}
id={x.id}
imgSrc={x.imgSrc}
bookmark={x.bookmark}
/>
);
})}
</>
</section>
</>
)
}
export function BookmarkCardContainer(props) {
const dispatch = useDispatch()
const [isBlue, setIsBlue] = useState(true);
const { informCardLists } = useSelector((state) => state.informCardLists);
const handdleBookmark = (e) => {
e.preventDefault()
setIsBlue(!isBlue)
let temp = JSON.parse(JSON.stringify(informCardLists))
temp[e.currentTarget.dataset.id].bookmark = !temp[e.currentTarget.dataset.id].bookmark
dispatch(setInformCardList(temp));
};
return (
<>
<svg
onClick={handdleBookmark}
data-id={props.id - 1}
className="inform_bookmark_emozi"
fill="none"
width="24"
height="24"
viewBox="0 0 18 18"
></svg>
/
</>
);
}
좋은 정보 감사합니다