이번 프로젝트를 하다가 한 페이지에 3가지 케이스의 멀티 input을 가지는 화면이 렌더링되는 부분이 있었다.
가령 코드 구조는 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import { ChangeEvent , useState } from "react" ;import { useRecoilState } from "recoil" ;import { backtestState } from "../atom" ;import BacktestInputs from "../components/BacktestInputs/BacktestInputs" ;function Backtest ( ) { const [backtest, setBacktest] = useRecoilState (backtestState); const [backtestInputs, setBacktestInputs] = useState ({ invest : "" , port : "" , dol : "" , }); const onChange = (e: ChangeEvent<HTMLInputElement> ) => { const { value, name } = e.target ; setBacktestInputs ({ ...backtestInputs, [name]: value }); }; const onSave = ( ) => { setBacktest (backtestInputs); }; const onReset = ( ) => { setBacktestInputs ({ invest : "" , port : "" , dol : "" }); }; return ( <> <button onClick ={onSave} > 저장</button > <BacktestInputs value ={backtestInputs} onChange ={onChange} /> <button onClick ={onReset} > input 값 리셋</button > <h2 > 전역상태</h2 > <ul > <li > invest: {backtest["invest"]}</li > <li > port: {backtest["port"]}</li > <li > dol: {backtest["dol"]}</li > </ul > </> ); } export default Backtest ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import styled from "@emotion/styled" ;import { ChangeEvent } from "react" ;interface Props { value : { invest : string, port : string, dol : string }; onChange : (e: ChangeEvent<HTMLInputElement> ) => void ; } function BacktestInputs ({ value, onChange }: Props ) { const { invest, port, dol } = value; return ( <> <h1 > Backtest</h1 > <InputWrap > <label htmlFor ="invest" > Investment: </label > <input type ="text" name ="invest" value ={invest} onChange ={onChange} id ="invest" /> </InputWrap > <InputWrap > <label htmlFor ="port" > Port: </label > <input type ="text" name ="port" value ={port} onChange ={onChange} id ="port" /> </InputWrap > <InputWrap > <label htmlFor ="dol" > Dual: </label > <input type ="text" name ="dol" value ={dol} onChange ={onChange} id ="dol" /> </InputWrap > </> ); } export default BacktestInputs ;const InputWrap = styled.div ` height: 50px; ` ;
나는 고민을 하였다. Backtest 페이지에서 Input을 감싸고 있는 컴포넌트가 3종류가 있고, 3종류의 컴포넌트 내부에는 다수의 input 값을 가지고 있을 때, 어떻게 input을 관리하면 좋을지 고민했다.
그렇게 하다가 생각해낸 방법이 각 컴포넌트의 input 값의 name을 가지는 객체로 input들의 상태를 관리하기로 했다.
나는 전역상태를 직접 onChange 이벤트가 일어날 때 마다 바꿔주는 코드를 작성했었다. 전역상태는 최소한으로 조작을 해야지만 에러가 덜 발생하기 때문에 최종적으로 저장 버튼을 클릭했을 때만 전역상태에 저장하기로 했다.
그래서 input 상태를 객체로 가지고 저장 버튼을 클릭했을 때, 전역 상태 update 함수에게 input 상태를 파라미터로 전달하도록 구현하였다.
소감 처음에는 그 많은 input을 직접 전달해줘야하나 … 걱정을 했었다. 하지만 객체로 input을 관리하고, input 마다 name 속성을 사용하여 onChange 이벤트로 controlled input을 다룰 수 있다는 것을 알게되어서 앞으로 다중 input 상태관리는 이러한 방법으로 접근하면 된다는 것을 알게되었다.