상태는 2가지로 나눌 수 있다.
- 상태 변경이 일어나는 곳
- 상태 변경의 영향을 받는 곳
side effect에 의존적인 상태
'장바구니 목록 데이터' 가 서버에 있다면 fetch와 같은 네트워크 요청이 필요하고
이때 데이터 로딩 여부(isLoading)상태가 true/false 인지에 따라 "로딩 중"의 화면을 보여주게 되면
=> 이것이 바로 side effect에 의존적인 상태이다.
input box
, select box
등과 같이 입력값을 받는 경우가 해당된다But, 상태 관리 툴은 반드시 필요하진 않다. 대부분의 경우 "React 사고하기" 를 통해 해결 가능하다.
Redux
에 대해 배워보자.Q. 7시 방향에 있는 `Edit on StackBlitz`를 눌러서 StackBlitz에 접속하세요.
import React, { useState } from 'react';
import styled from 'styled-components';
const Container = styled.div`
border: 5px solid green;
padding: 10px;
margin: 10px;
position: relative;
`;
const Quantity = styled.h2`
text-align: center;
color: red;
border: 5px solid red;
padding: 3px;
`;
const Button = styled.button`
margin-right: 5px;
`;
const Text = styled.h1`
color: ${(props) => (props.color ? props.color : 'black')}
`;
export default function App() {
const [number, setNumber] = useState(1);
const plusNum = () => {
setNumber(number + 1);
};
const minusNum = () => {
setNumber(number - 1);
};
console.log('Parents');
return (
<Container>
<Text>[Parents Component]</Text>
<Text>
Child4 컴포넌트에 있는 버튼을 통해
<br /> state를 변경하려고 합니다.. 🤮
</Text>
<Text color="tomato">Props Driling이 발생!!</Text>
<Quantity>{`수량 : ${number}`}</Quantity>
<Child1 plusNum={plusNum} minusNum={minusNum} />
</Container>
);
}
function Child1(
{
/* props로 전달받은 plusNum, minusNum를 가져오세요 */
}
) {
console.log('Child1');
return (
<Container>
<Text>[Child 1 Component]</Text>
{/* plusNum, minusNum 함수를 props로 전달해주세요! */}
<Child2 />
</Container>
);
}
function Child2(
{
/* props로 전달받은 plusNum, minusNum를 가져오세요 */
}
) {
console.log('Child2');
return (
<Container>
<Text>[Child 2 Component]</Text>
{/* plusNum, minusNum 함수를 props로 전달해주세요! */}
<Child3 />
</Container>
);
}
function Child3(
{
/* props로 전달받은 plusNum, minusNum를 가져오세요 */
}
) {
console.log('Child3');
return (
<Container>
<Text>[Child 3 Component]</Text>
{/* plusNum, minusNum 함수를 props로 전달해주세요! */}
<Child4 />
</Container>
);
}
function Child4({ plusNum, minusNum }) {
console.log('Child4');
return (
<Container>
<Text>[Child 4 Component]</Text>
<Button onClick={plusNum}>👍</Button>
<Button onClick={minusNum}>👎</Button>
</Container>
);
}
import React, { useState } from 'react';
import styled from 'styled-components';
import { useSelector, useDispatch } from 'react-redux';
const Container = styled.div`
border: 5px solid green;
padding: 10px;
margin: 10px;
`;
const Quantity = styled.h2`
text-align: center;
color: red;
border: 5px solid red;
padding: 3px;
`;
const Button = styled.button`
margin-right: 5px;
`;
const Text = styled.h1`
color: ${(props) => (props.color ? props.color : 'black')}
`;
export default function App() {
const number = useSelector((state) => state);
console.log('Parents');
return (
<Container>
<Text>[Parents Component]</Text>
<Text>
Child4 컴포넌트에 있는 버튼을 통해 <br /> state를 변경하려고 합니다. ☺️
</Text>
<Text color="tomato">(Redux를 사용하는 경우)</Text>
<Quantity>{`수량 : ${number}`}</Quantity>
<Child1 />
</Container>
);
}
function Child1() {
console.log('Child1');
return (
<Container>
<Text>[Child 1 Component]</Text>
<Child2 />
</Container>
);
}
function Child2() {
console.log('Child2');
return (
<Container>
<Text>[Child 2 Component]</Text>
<Child3 />
</Container>
);
}
function Child3() {
console.log('Child3');
return (
<Container>
<Text>[Child 3 Component]</Text>
<Child4 />
</Container>
);
}
function Child4() {
const dispatch = useDispatch();
const plusNum = () => {
dispatch({ type: 'Plus' });
};
const minusNum = () => {
dispatch({ type: 'Minus' });
};
console.log('Child4');
return (
<Container>
<Text>[Child 4 Component]</Text>
<Button onClick={plusNum}>👍</Button>
<Button onClick={minusNum}>👎</Button>
</Container>
);
}
Q. Child6 에 있는 👋 버튼을 누르면 Child3에 느낌표가 하나씩 추가되는 간단한 애플리케이션을 만들자.
- 이 때, Child3, Child6이 하나의 상태를 공유하기 때문에 최상위 컴포넌트인 App에서 상태를 관리해야 한다.
-> 때문에 상태를 변경할 때마다 App 컴포넌트가 리렌더링 되면서 모든 컴포넌트가 리렌더링된다.
=> 변경되는 상태와 연관 없는 컴포넌트까지 불필요하게 리렌더링되는 현상을 해결하자.
import * as React from 'react';
import './style.css';
import styled from 'styled-components';
import { useState } from 'react';
const Component = styled.div`
border: 3px solid green;
border-radius: 10px;
flex-grow: 1;
line-height: 30px;
text-align: center;
margin: 10px;
>button{
margin-left: 10px;
}
`;
const Container = styled.div`
display: flex;
width: 100%;
justify-contents: center;
`;
export default function App() {
const [greeting, setGreeting] = useState('Hello');
console.log('App');
return (
<Container>
<Component>
App
<Container>
<Child1 greeting={greeting} setGreeting={setGreeting} />
<Child2 greeting={greeting} setGreeting={setGreeting} />
</Container>
</Component>
</Container>
);
}
function Child1({ greeting, setGreeting }) {
console.log('Child1');
return (
<Component>
Child1
<Container>
<Child3 greeting={greeting} setGreeting={setGreeting} />
<Child4 />
</Container>
</Component>
);
}
function Child2({ greeting, setGreeting }) {
console.log('Child2');
return (
<Component>
Child2
<Container>
<Child5 />
<Child6 greeting={greeting} setGreeting={setGreeting} />
</Container>
</Component>
);
}
function Child3({ greeting, setGreeting }) {
console.log('Child3');
return <Component>Child3 : {greeting} </Component>;
}
function Child4() {
console.log('Child4');
return <Component>Child4</Component>;
}
function Child5() {
console.log('Child5');
return <Component>Child5</Component>;
}
function Child6({ greeting, setGreeting }) {
console.log('Child6');
return (
<Component>
Child6
<button onClick={() => setGreeting(greeting + '!')}>👋</button>
</Component>
);
}
import * as React from 'react';
import './style.css';
import styled from 'styled-components';
import { useSelector, useDispatch } from 'react-redux';
const Component = styled.div`
border: 3px solid green;
border-radius: 10px;
flex-grow: 1;
line-height: 30px;
text-align: center;
margin: 10px;
>button{
margin-left: 10px;
}
`;
const Container = styled.div`
display: flex;
width: 100%;
justify-contents: center;
`;
export default function App() {
console.log('App');
return (
<Container>
<Component>
App
<Container>
<Child1 />
<Child2 />
</Container>
</Component>
</Container>
);
}
function Child1() {
console.log('Child1');
return (
<Component>
Child1
<Container>
<Child3 />
<Child4 />
</Container>
</Component>
);
}
function Child2() {
console.log('Child2');
return (
<Component>
Child2
<Container>
<Child5 />
<Child6 />
</Container>
</Component>
);
}
function Child3() {
const greeting = useSelector((state) => state);
console.log('Child3');
return <Component>Child3 : {greeting} </Component>;
}
function Child4() {
console.log('Child4');
return <Component>Child4</Component>;
}
function Child5() {
console.log('Child5');
return <Component>Child5</Component>;
}
function Child6() {
console.log('Child6');
const dispatch = useDispatch();
const addBang = () => {
dispatch({ type: 'AddBang' });
};
return (
<Component>
Child6
<button onClick={addBang}>👋</button>
</Component>
);
}