1주차발표자료 조찬기 - TECH-SHARING-STUDY/FE_STUDY GitHub Wiki
- store는 오직 하나만 존재한다.
- store의 state는 오직 action을 통해서만 변경할 수 있다.
- reducer는 pure function이다.
스토어를 만들어 최상단에 위치한다.
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { createStore } from "redux";
import { Provider } from "react-redux";
const store = createStore(/*your root reducer*/);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
상태를 변경할 때는 dispatch를 이용한다.
import React, { Component } from "react";
import { action1 } from "../actions";
class Button extends Component {
doSomething(event) {
this.props.store.dispatch(action1());
}
render() {}
}
export default Button;
사용할 때는 store.getState를 이용해 state를 사용
import React, { Component } from "react";
class Counter extends Component {
render() {
return (
<div>
<h1>Value : {this.props.store.getState().some.value}</h1>
</div>
);
}
}
export default Counter;
Provider와 Consumer를 만들어 export해준다.
import React, { Component, createContext } from "react";
const Context = createContext(); // Context 를 만듭니다.
const { Provider, Consumer: SampleConsumer } = Context;
// Provider 에서 state 를 사용하기 위해서 컴포넌트를 새로 만들어줍니다.
class SampleProvider extends Component {
state = {}; // state
actions = {}; // setState 등을 이용한 state 변화 함수들
render() {
const { state, actions } = this;
const value = { state, actions };
return <Provider value={value}>{this.props.children}</Provider>;
}
}
export { SampleProvider, SampleConsumer };
최상단 컴포넌트에 Provider를 감싼다.
import React from "react";
import { SomeProvider } from "./contexts/sample";
const App = () => {
return (
<SomeProvider>
<InnerComponents />
</SomeProvider>
);
};
export default App;
전역 state를 사용하고 싶은 곳에서 Consumer 컴포넌트를 상위에 감싼다.
그 후 state로 상태 값을, actions로 상태 변경을 수행할 수 있다.
import React from "react";
import { SampleConsumer } from "../contexts/sample";
const Receives = () => {
return (
<SampleConsumer>
{({ state, actions }) => (
<Sends value={state.value} setValue={actions.setValue} />
)}
</SampleConsumer>
);
};
export default Receives;
하나의 Provider, Consumer에 모든 전역상태를 다 때려박아야하나요??
여러개로 나눌 수도 있지만...
Provider가 많아지면 depth가 증가함
return (
<SampleProvider>
<AnotherProvider>
<NewProvider>
<WhatTheProvider>
{... Provider 지옥}
</WhatTheProvider>
</NewProvider>
</AnotherProvider>
</SampleProvider>
);
createElement 를 이용해서 Provider를 하나로 합치는 것도 가능
import React from "react";
// Provider1, 2, 3 ... 이 있다고 할 때
// context props로 [Provider1, Provider2, ... ] 를 설정
const AppProvider = ({ contexts, children }) =>
contexts.reduce(
(prev, context) =>
React.createElement(context, {
children: prev,
}),
children
);
최 상단의 Provider 들을 합친 하나의 Provider로 감싸기
Consumer의 사용은 동일합니다.
const App = () => {
return (
<AppProvider contexts={[SampleProvider, AnotherProvider]}>
<div className="panes">
<LeftPane />
<RightPane />
</div>
</AppProvider>
);
};
기능 | Redux | Context API |
---|---|---|
전역상태저장 | store | 컴포넌트 (Provider) |
저장소 state 변경 | dispatch, reducer의 action | 컴포넌트의 메소드 |
전역상태 사용 | store.getState | 컴포넌트 (Consumer) |
Redux는 Redux를 사용하기 위해 프로젝트에 import 해야 할 라이브러리
라이브러리를 사용하는 것은 프로젝트의 번들 크기를 늘려 앱이 로드되는 데에 걸리는 시간을 증가시킨다.
라이브러리들을 적절한 이유 없이 사용해서는 안된다.
You Might Not Need Redux - Dan Abramov
- 개발하고 있는 앱이 많은 상태를 저장할 필요가 없다면
- 컴포넌트 구조가 과도한 prop drilling을 피할 수 있을만큼 단순하다면
모든 상태 관리 라이브러리는 사용할 필요가 없다.
(prop drilling : 프로퍼티 내리꽂기. 필요한 위치에 두기 위해서 프로퍼티를 내려 구멍을 내서 전달)
- 로컬 스토리지에 상태를 영속적으로 저장하고 시작할 때 다시 불러올 때
- 상태를 서버에서 미리 채워서 HTML에 담아 클라이언트로 보내고 앱을 시작할 때
- 사용자의 액션을 직렬화해서 상태와 함께 자동으로 버그 리포트에 첨부 (로깅)
- 액션 객체를 네트워크를 통해 보내면 코드를 크게 바꾸지 않고도 협업 환경을 구현할 수 있습니다.
- 실행취소 내역의 관리나 낙관적인 변경(optimistic mutations)을 코드를 크게 바꾸지 않고도 구현할 수 있습니다.
- 개발할 때 상태 내역 사이를 오가고 액션 내역에서 현재 상태를 다시 계산하는 일을 TDD 스타일로 할 수 있습니다.
- 개발자 도구에게 완전한 조사와 제어를 가능하게 해서 개발자들이 자신의 앱을 위한 도구를 직접 만들 수 있게 해 줍니다.
- 비즈니스 로직 대부분을 재사용하면서 UI를 변경
Context API는 high-frequency updates에 성능저하가 발생합니다.
Redux는 그렇지 않습니다
(이렇게 자주 바뀌는 상황에서는 vue가 React보다 유리합니다.)
- 오직 전역 상태 관리를 위한다면 Context API를 사용하라.
- 상태 관리 외에 여러 기능이 필요하다면 Redux 를 사용하라.
- high-frequency한 어플리케이션의 경우 Context API를 사용하면 성능상 이슈가 있을 수 있다.