제작 중인 프로젝트에서 Modal을 직접 제작하는 중이였다. 공통적으로 사용되는 Modal 배경을 전역에 만들어 놓고 Modal의 표시 여부와 내부 content를 Redux State로 만들어서 작동시키겠다는 생각이였다.
문제는 content를 React Element를 Redux의 State로 직접 넣어서 구현을 한 것이다. 작동에는 문제가 없었지만 곧 문제가 생겼다. 문제가 생긴 코드는 아래 코드와 같은 구조였다.
React Element와 Component 차이
최상단 App.js
import React, {useState} from 'react';
import ReactDOM from 'react-dom';
import {connect} from 'react-redux';
import {show} from './store/reducers/modal';
import Modal from './components/modal';
const App = ({isVisible, show}) => {
return (
<>
<button onClick={()=>{show('search');}}>Redux로 검색창 열기</button>
<Modal/>
</>
)
}
const mapStateToProps = (state) => ({
isVisible: state.modal.isVisible
});
const mapDispatchToProps = (dispatch) => ({
show: (content) => dispatch(show({content})),
});
export default connect(mapStateToProps,mapDispatchToProps)(App);
최상단에서 렌더링되는 modal.js
import React from 'react';
import {connect} from 'react-redux';
import {drop} from '../store/reducers/modal';
import {useEffect} from 'react';
import * as modals from './modals';
import styles from './modal.module.css'
const Modal = ({isVisible, content, drop}) => {
const checkEsc = (e) => {
if (e.code == 'Escape')
drop();
}
const Content = modals[content];
useEffect(()=>{
if(isVisible)
{
window.addEventListener('keydown', checkEsc);
}
else
window.removeEventListener('keydown',checkEsc);
return ()=>{window.removeEventListener('keydown',checkEsc)};
}, [isVisible])
return (
<>
{isVisible &&
<div className={styles.modalContainer}>
<div className={styles.closeBar}>
<button onClick={drop}>XXXX</button>
</div>
<Content drop ={drop} />
</div>}
</>
);
}
const mapStateToProps = (state) => ({
isVisible: state.modal.isVisible,
content: state.modal.content
});
const mapDispatchToProps = (dispatch) => ({
drop: () => dispatch(drop()),
});
export default connect(mapStateToProps, mapDispatchToProps)(Modal);
content는 검색을 받는 컴포넌트였다. content에서 검색 버튼을 누르고 나면 Modal이 닫히게 하기 위해 drop 기능을 하는 함수를 prop으로 내려주려고 했다. React Element에는 prop을 넘기는 법을 몰라 검색을 하다가 이렇게 React 구성 요소를 Redux State에 저장하는 것은 권장하지 않는다는 글을 보게 되었다. (나중에 찾긴 했는데 내 방식대로 굳이 해결을 하자면 React Component를 넘기면 되긴한다.)
그러면 안되는 것은 아니지만 Redux의 핵심 설계 중 하나인 store안의 state의 지속성과 재수화(rehydration, 대체?)가 불가능해 time travel debugging을 사용할 수가 없게 된다(redux-devtools). Redux를 사용해야할 이유가 적어지는 것이다.
redux-persist 동작 원리 - rehydration에 대해 알려줌!
Redux는 plain serializable objects(적절한 용어를 못찾음..)와 arrays, 원시 값들을 store에 저장하기를 매우 권장한다.
++ 리덕스에서는 앱 전체에서 필요한 전역 상태만 리덕스 스토어에 저장해야한다. 한 곳에서만 필요한 상태는 컴포넌트에서 관리되어야 한다.
고치는 과정은 다음에 쓰겠다.