Why Redux?
지난 주에 순수 react를 가지고 MAC의 미리 알림 애플리케이션을 따라해볼 기회가 있었다. 검색창과 오늘/예정, 리스트 추가/보기, 각 카테고리에 따른 완료/진행중인 계획을 볼 수 있는 앱이였다. 기본적인 과제로는 검색창, 리스트추가/보기, 각각 리스트에 따른 계획을 완료/비완료로 나누는 것이었지만, 나는 최신 기능도 함께 구현하고 싶어 욕심을 내었다.
결과적으론 실패했다. 리스트나 카테고리(오늘/예정)에 들어가서 완료/진행중을 조작하면, 갑자기 선택한 리스트와 관련없는 전체 계획이 나타나는 식으로 스테이트 관리가 어려워 실패로 끝났다. state가 위에서 아래로 흐르는 일방적인 리액트을 가지고, 내가 구현하고자 하는 한 페이지 어플리케이션 하려니, 나중엔 내 논리에 꼬여 state가 어떻게 관리되는지 알 수 없게 된 것이다. App -> listEntry 로 state를 내려보내야 할때, Nav 혹은 list 컴포넌츠에선 굳이 넘겨 받지 않아도 되는 state들을 넘겨주어야 할 때도 있었다. 극단적인 경우로 list.js 에선 무려 7개가 넘는 state를 넘겨받곤 했다. 이렇게 기초적인 to-do list를 구현하는것도 이렇게 복잡하고 머리가 아픈데, 더 복잡한 어플리케이션을 내가 배운 수준의 리액트로만 구현해야한다면, state 관리때문에 리액트 사용을 포기하고 말것이다. (물론, 보완재가 있겠지..? 라우터라던가...?) 개발자들은 언제나 문제를 해결하고자 하는 습관이 있기 때문에, 일방적으로 흐르는 state를 한번에 모아서 관리하고자 하는 노력이 있었다.
Redux는 State Management Tool 이다. Component 안에서 관리되던 state를 컴포넌트 밖으로 꺼내 Store라는 공간에 모아놓았다. 각각의 component는 가상의 store 를 이용하여 부모의 state를 넘겨 받지 않아도 직접적으로 state를 get 하고, 바꿀 수 (직접X) 있는 것이다. redux는 자바스크립트에 사용할 수 있는 라이브러리이기 때문에 리액트가 아닌 타 자바스크립트 베이스의 프레임워크와 함께 쓸 수 있다. 다만, 리액트에서 가장 잘 활용된다. react-redux는 리액트용 리덕스이다. 해당 패키지를 다운 받을 때는 반드시 react-redux를 이용해줘야 한다.
Store
: state를 저장하는 저장소다.
시조의 컴포넌트에 <Provider store = {store}></Provider> 를 이용해서 어느 컴포넌트에서나 Store에 접근 할 수 있도록 해주어야 한다.
//보통은 index.js 가 시조 컴포넌트일 때가 많으므로
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
Action
: 이벤트와 비슷함. Store에 데이터를 보내는 유일한 방법. Action 은 Action Creator와 함께 한다.
const INCREMENT = 'INCREMENT';
const increment = (data) => {
return {
type : INCREMENT,
addBy : data
}
}; // 리턴되는 object는 action, increment 함수는 action creator
dispatch
: only way to trigger a state change
Action 은 dispatch를 통해서 사용될 수 있다. 따라서 state를 바꿀 수 있는 유일한 수단이 된다.
자매품으로 mapDispatchToProps()가 있다.
const mapDispatchToProps = dispatch => {
return {
current: category => dispatch(changeCategory(category))
};
};
여기서 current는 내가 만든 props 중 일부다. 마음대로 이름 붙여도 된다. changeCategory는 action.js 에서 가져온 내가 정한 module 중 하나. 바꾸고자 하는 데이터를 dispatch 인수로 받아 ->action 에 넘겨주고 -> action 타입에 따라 reducer가 실행되는 구조.
ref 접근
react에선 DOM의 인자를 그대로 가져오는 document.querySelector()의 방법을 권하지 않는다고 한다. 그런데 입력창과 입력창의 값을 제출하는 기능을 가진 버튼을 따로 둘 땐 어떻게 해야 할까? 물론 다양한 방법이 있다. 나는 귀찮으니까 바로 ref를 지정해서 그 값을 가져오는 방법을 선택했다. 하지만 공식문서에 따르면 ref를 남발할 경우, ref를 찾기 위해 한참을 헤매야 할 수도 있기 때문에 과도한 사용은 지양하라고 나와 있다.
export default class Nav extends Component {
handleNewPlan() {
let input = this.refs.input;
//중략
this.props.add(input.value); // 인풋 값을 받아 action에 제출
}
render() {
return (
<div>
<form onSubmit={this.handleNewPlan.bind(this)}>
<input
type="text"
ref="input"
></input>
<button type="submit">
Add Todo
</button>
</form>
</div>
);
}
}
reducer
: Reducers specify how the application's state changes in response to actions sent to the store. Remember that actions only describe what happened, but don't describe how the application's state changes (출처)
reducer는 순수한 함수다. 현재의 state를 가져옴 -> action을 수행함 -> 새로운 state를 리턴하는 순수한 함수. reducer는 시조의 컴포넌트에서 store와 연결된다. 중요한 점은 createStore()는 reducer, middleware순으로 인자를 써줘야 한다.
const store = createStore(todoReducer, applyMiddleware(logger));
- redux에서 action / reducer / store를 각각 따로 두는 이유? => 앱이 복잡해질 수록 각각 따로 관리하는게 유지보수 등 여러 면에서 편함.
- react-redux하면서, react 스러운 것들을 안쓰려 노력했는데, 써야할 때도 있다. 굳이 store에서 관리 하지 않고 해당 컴포넌트 안에서 소진되고 하는 것들은 그냥 그 컴포넌트에 state 넣고 쓰면 된다.
- 지금은 DB를 사용하지 않아 데이터를 수정/삭제할 때 비효율적인 면을 느낄 수 있다.
- 지난번 리액트만을 이용해서 todolist를 사용할 때, 수정할 데이터를 찾을 때 데이터 내용으로 찾았는데, 데이터에 id라는 고유한 번호를 붙여주면, 나중에 고유한 아이디를 찾아서 수정/삭제 하면 된다.
- 삼항 연산자를 잇달아 사용하면, 코드의 가독성이 떨어진다. 하위 컴포넌트에서 해결할 수 있도록 고민해봐.
- 정보는 어디 단계에서 관리하면 좋을까? (리액트)
- 내가 만든 애플리케이션을 남에게 말할땐, 비전문가인 고객에게 해당 애플리케이션을 소개한다고 생각할 것.
- 변수에 이름을 붙일 땐, 협업을 생각하고 남이 봐도 직관적으로 역할을 가늠할 수 있게 하는 변수명이 좋다.
'2. 우당탕탕 개발자 > 2-1. 공부기록' 카테고리의 다른 글
13Mar2020 TIL (0) | 2020.03.13 |
---|---|
11Mar2020 TIL (0) | 2020.03.12 |
24Feb2020 TIL (0) | 2020.02.25 |
23Feb2020 TIL (0) | 2020.02.23 |
18Feb2020 TIL (0) | 2020.02.19 |
댓글