React.Js의 상태 관리
리버풀 FC 대 맨체스터 유나이티드를 위한 간단한 스코어보드 미니 앱을 개발했습니다. 좋은 생각이죠?
다음은 어떻게 다운되었는지에 대한 몇 가지 주요 사항입니다.
useState
import {useState} from 'react'
import './App.css';
import ManchesterUnited from './assets/images/manchester-united.png';
import LiverpoolFC from './assets/images/liverpool-fc.png';
function App() {
const initialScoreBoard = { home: 0, away: 1 };
const [scores, setScores] = useState(initialScoreBoard);
const incrementScore = (team) => {
team === 'home'
? setScores({ home: scores.home++, ...scores })
: setScores({ away: scores.away++, ...scores });
}
const decrementScore = (team) => {
if (team === 'home') {
if (scores.home === 0) return;
setScores({ home: scores.home--, ...scores })
}
if (team === 'away') {
if (scores.away === 0) return;
setScores({ away: scores.away--, ...scores });
}
};
return (
<div className="App">
<div className="score-board">
<img
className=""
width="180"
height="240"
src={LiverpoolFC}
alt="Liverpool FC"
/>
<h1>{scores.home}</h1>
<h1>{scores.away}</h1>
<img
className=""
width="240"
height="240"
src={ManchesterUnited}
alt="Liverpool FC"
/>
</div>
<div>
<button onClick={() => incrementScore('home')}>Goal!!!</button>
<button onClick={() => decrementScore('home')}>Reverse Goal!!!</button>
<button onClick={() => incrementScore('away')}>Goal!!!</button>
<button onClick={() => decrementScore('away')}> Reverse Goal!!!</button>
</div>
</div>
);
}
export default App;
useReducer
import { useReducer } from 'react';
import './App.css';
import ManchesterUnited from './assets/images/manchester-united.png';
import LiverpoolFC from './assets/images/liverpool-fc.png';
function App() {
const INITIAL_STATE = {
scores: { home: 0, away: 1 },
};
const SCORE_ACTION_TYPES = {
SET_SCORES: 'SET_SCORES',
};
const scoreBoardReducer = (state, action) => {
const { type, payload } = action;
switch (type) {
case SCORE_ACTION_TYPES.SET_SCORES:
return { scores: payload, ...state };
default:
throw new Error(`Invalid action ${type}`);
}
};
const setScores = (scores) => {
dispatch({ type: SCORE_ACTION_TYPES.SET_SCORES, payload: scores });
};
const [{ scores }, dispatch] = useReducer(scoreBoardReducer, INITIAL_STATE);
const incrementScore = (team) => {
team === 'home'
? setScores({ home: scores.home++, ...scores })
: setScores({ away: scores.away++, ...scores });
};
const decrementScore = (team) => {
if (team === 'home') {
if (scores.home === 0) return;
setScores({ home: scores.home--, ...scores });
}
if (team === 'away') {
if (scores.away === 0) return;
setScores({ away: scores.away--, ...scores });
}
};
return (
<div className="App">
<h1>Score Board</h1>
<div className="score-board">
<img
className=""
width="180"
height="240"
src={LiverpoolFC}
alt="Liverpool FC"
/>
<h1>{scores.home}</h1>
<h1>{scores.away}</h1>
<img
className=""
width="240"
height="240"
src={ManchesterUnited}
alt="Liverpool FC"
/>
</div>
<div>
<button onClick={() => incrementScore('home')}>Goal!!!</button>
<button onClick={() => decrementScore('home')}>Reverse Goal!!!</button>
<button onClick={() => incrementScore('away')}>Goal!!!</button>
<button onClick={() => decrementScore('away')}> Reverse Goal!!!</button>
</div>
</div>
);
}
export default App;
컨텍스트 API + useState
import { useState, createContext } from 'react';
const initialScoreBoard = { home: 0, away: 1 };
/**
* Create Context with default state
*/
export const ScoreContext = createContext({
score: initialScoreBoard,
incrementScore: () => null,
decrementScore: () => null,
});
/**
* Implement useState for state mgt
* Expose useState to Context Provider for Accessibility
* return Context Provider
*/
export const ScoreProvider = ({ children }) => {
const [scores, setScores] = useState(initialScoreBoard);
const incrementScore = (team) => {
team === 'home'
? setScores({ home: scores.home++, ...scores })
: setScores({ away: scores.away++, ...scores });
};
const decrementScore = (team) => {
if (team === 'home') {
if (scores.home === 0) return;
setScores({ home: scores.home--, ...scores });
}
if (team === 'away') {
if (scores.away === 0) return;
setScores({ away: scores.away--, ...scores });
}
};
const value = { scores, incrementScore, decrementScore };
return (
<ScoreContext.Provider value={value}>{children}</ScoreContext.Provider>
);
};
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { ScoreProvider } from './context/scores.context';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<ScoreProvider>
<App />
</ScoreProvider>
</React.StrictMode>
);
import { useContext } from 'react';
import './App.css';
import ManchesterUnited from './assets/images/manchester-united.png';
import LiverpoolFC from './assets/images/liverpool-fc.png';
import { ScoreContext } from './context/scores.context';
function App() {
const { scores, incrementScore, decrementScore } = useContext(ScoreContext);
return (
<div className="App">
<h1>Score Board</h1>
<div className="score-board">
<img
className=""
width="180"
height="240"
src={LiverpoolFC}
alt="Liverpool FC"
/>
<h1>{scores.home}</h1>
<h1>{scores.away}</h1>
<img
className=""
width="240"
height="240"
src={ManchesterUnited}
alt="Liverpool FC"
/>
</div>
<div>
<button onClick={() => incrementScore('home')}>Goal!!!</button>
<button onClick={() => decrementScore('home')}>Reverse Goal!!!</button>
<button onClick={() => incrementScore('away')}>Goal!!!</button>
<button onClick={() => decrementScore('away')}> Reverse Goal!!!</button>
</div>
</div>
);
}
export default App;
컨텍스트 API + useReducer
import { useReducer, createContext } from 'react';
const initialScoreBoard = { home: 0, away: 1 };
/**
* Create Context with default state
*/
export const ScoreContext = createContext({
scores: initialScoreBoard,
incrementScore: () => null,
decrementScore: () => null,
});
/**
* Implement useState for state mgt
* Expose useState to Context Provider for Accessibility
* return Context Provider
*/
export const ScoreProvider = ({ children }) => {
const INITIAL_STATE = {
scores: { home: 0, away: 1 },
};
const SCORE_ACTION_TYPES = {
SET_SCORES: 'SET_SCORES',
};
const scoreBoardReducer = (state, action) => {
const { type, payload } = action;
switch (type) {
case SCORE_ACTION_TYPES.SET_SCORES:
return { scores: payload, ...state };
default:
throw new Error(`Invalid action ${type}`);
}
};
const setScores = (scores) => {
dispatch({ type: SCORE_ACTION_TYPES.SET_SCORES, payload: scores });
};
const [{ scores }, dispatch] = useReducer(scoreBoardReducer, INITIAL_STATE);
const incrementScore = (team) => {
team === 'home'
? setScores({ home: scores.home++, ...scores })
: setScores({ away: scores.away++, ...scores });
};
const decrementScore = (team) => {
if (team === 'home') {
if (scores.home === 0) return;
setScores({ home: scores.home--, ...scores });
}
if (team === 'away') {
if (scores.away === 0) return;
setScores({ away: scores.away--, ...scores });
}
};
const value = { scores, incrementScore, decrementScore };
return (
<ScoreContext.Provider value={value}>{children}</ScoreContext.Provider>
);
};
이 실습에서 얻은 교훈은 컨텍스트 API가 높은 수준의 추상화를 제공하고 상태가 필요한 여러 구성 요소에서 동일한 논리로 구현된 useState 및 useReducer와 비교하여 DRY 원칙을 활용하여 부모 구성 요소와 해당 자식이 상태에 액세스할 수 있도록 한다는 것입니다.
useState 및 useReducer는 컨텍스트 API와 독립적으로 사용할 수 있지만 상태 관리가 성장함에 따라 컨텍스트 API에 완벽하게 맞습니다.
변경해야 할 모든 것이 단일 상태 값이고 자세한 상용구를 고려할 때 useReducer를 구현하는 것은 정말 과잉입니다. useReducer는 액션이 여러 상태 값을 변경할 때 유용합니다. 카트에 항목을 추가할 때 카트 시스템에서 - 항목 수, 카트에 있는 항목, 카트에 있는 항목의 총 비용 및 복잡성에 따라 더 많을 수 있습니다.
링크: https://react-ts-dguw1i.stackblitz.io/
읽어주셔서 감사합니다. 이것에 대해 어떻게 생각하세요?
추신: 곧 이 게시물에 redux와 그 첨가제를 추가할 예정입니다. 이 공간을 조심하세요
Reference
이 문제에 관하여(React.Js의 상태 관리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/omohemma/state-management-in-reactjs-49m2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)