개발자
안녕하세요 react를 이용해서 복잡한 작성 페이지를 만들고있습니다. 아래의 타입은 예시입니다. type payload = { name: string; message: string; type: string; url: { pc: string; mobile: string; }; contents: { images: { url: string; name: string; }[]; buttons: { name: string; url: string; }[]; }; conditions: { ... }, .... }; 위처럼 복잡한 데이터를 서버로 보내줘야해서 데이터를 관리해야하는데 현재는 페이지내에 구조가 복잡하고 컴포넌트도 매우많아 props drilling이 너무 심해질거같아서 recoil, jotai와 같은 상태관리 라이브러리를 이용해서 작업을 진행하고있습니다. 이러한 상황에서 관리하는 데이터를 한객체에 모아서 관리하는게 좋은지 아니면 const nameAtom = atom(''); const messageAtom = atom(''); const typeAtom = atom(''); const urlAtom = atom({ pc: '', mobile: ''}); .... 처럼 일일히 쪼개서 관리하는게 맞는 방향인지 모르겠어서 질문드립니다 ! (사수가없어서 물어볼곳이없어요...) 현재는 아래와같이 쪼개서 작업한뒤 submit시에 합쳐주는 방식으로 구현해놓았는데 atom 갯수가 20개 정도 되버리니까 너무 복잡해보여서 이게맞나... 싶어서 질문드리게되었습니다.
답변 2
안녕하세요! 상태관리 관련 자주 고민하게되는 부분에 대한 질문을 주셨네요! 사실 완전 정답은 없기 때문에 앱의 성능 최적화와 DX 사이에서의 적당한 타협점을 찾는게 나름의 요령 아닐까 싶습니다🥲 먼저 질문자님의 방식처럼 atom을 나눠 사용하게 되면 컴포넌트 별로 필요한 데이터만 사용하고 업데이트 하며 렌더링을 최적화하기에 용이하다는 장점이 있지만, 말씀하신대로 관리하기가 너무 복잡해질 수 있습니다. 반대로 한 객체에 모아 관리하게 되면 사용은 편리하지만, 하나의 프로퍼티만 업데이트 되어도 그 객체를 참조중인 모든 컴포넌트가 업데이트 된다는 점에서 렌더링 최적화에 대한 고민이 생기기도 합니다. 일단 위와 같은 상황에서 저의 추천은 "한 객체에 모아 관리하기" 입니다! 후에 어차피 submit시에 내용을 다시 합쳐줘야 하는 구조라면 굳이 다 분리 시켜놔야할 이유가 없기도 하니까요. 대신, 렌더링 이슈가 고민이 된다거나 프로퍼티 개별관리가 필요한 케이스에는 selector 와 selectorFamily를 활용하시면 될 듯 합니다! (Jotai에서는 selectAtom 등 활용) 공식문서를 찾아보시면 제일 좋고, 관련해서 간단한 사용법 정리해둔 블로그를 찾아서 함께 공유드려요! https://velog.io/@2ast/React-Recoil-selector%EB%A1%9C-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%B5%9C%EC%A0%81%ED%99%94%EC%97%90-%EA%B8%B0%EC%97%AC%ED%95%98%EA%B8%B0
안녕하세요. 제가 생각으로는 위에서 말씀하신 것과 같이 복잡한 form를 구현할 경우에는 recoil, jotai와 같은 atomic 구조의 라이브러리 보다는 zustand와 redux를 사용하는 것이 더 좋을 것 같다는 생각이 듭니다. atom을 변수값을 작은 단위로 구성하면 스프레드 연산(...)등을 활용해서 전송할 데이터를 통합해야 하는 번거로움이 있을 것 같습니다. zustand로 store.ts 파일에 사용할 API 타입과 state를 정의한 후에 입력하는 단위로 컴포넌트를 나눈 뒤에 사용하는 컴포넌트 UI에서 데이터를 입력하면 상태값을 구독하고 변경하도록 하는 방법을 고려해 볼수 있을것 같습니다. 아울러, 데이터 입력시에 유효성 체크 같은 기능이 필요하다면, react-hook-form, formik과 같은 라이브러리를 사용하는 것을 권해드리고 싶습니다.
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
// store.ts type Payload = { name: string; message: string; type: string; url: { pc: string; mobile: string; }; contents: { images: { url: string; name: string; }[]; buttons: { name: string; url: string; }[]; }; const initialState : Payload = { name : ' ', message: ' ' , type: ' ', url: { pc: ' ', mobile: ' ', }, ... } export const usePayloadStore = create<Payload>((set) => ({ payloadInfo: initialState, setPayloadInfo: (newInfo) => set((state) => ({ payloadInfo: { ...state.payloadInfo, ...newInfo }, })) })); /////// Payload.tsx export default function Payload( ) { return( <> <Name/> <Message/> <Url/> <Contents/> ... </> ) } /////// Name.tsx export default function Name( ) { const name = usePayloadStore (state => state.payloadInfo.name ); const setPayloadInfo= usePayloadStore (state => state.setPayloadInfo); return( <Input onChange={(e : React.ChangeEvent<HTMLInputElement>) => { setPayloadInfo({name : e.target.value }) }} value={name} /> )
지금 가입하면 모든 질문의 답변을 볼 수 있어요!
현직자들의 명쾌한 답변을 얻을 수 있어요.
이미 회원이신가요?
지금 가입하면 모든 질문의 답변을 볼 수 있어요!