개발자
리스트 A 엔트리 컴포넌트 B A를 수정하는 함수 C 이렇게 있을 때 B에서 A를 수정해야 하는 상황입니다. 모바일 환경이라 최대한 엔트리 B를 최적화 하고 싶은데 memo를 해야할 때 함수C는 어떻게 최적화 해야할까요 A에 선언하면 A의 최신 값을 얻기 위해 C가 변경될 때 마다 B또한 C의 변경에 의해 재렌더링 될 것이니 기존에는 이런 재렌더링을 막기위해 setA( (prevA) => { ... } ) 와 같은식으로 setA 내부의 callback으로 A의 최신값을 사용해서 A를 C의 의존성 배열에 추가하는 것을 피해왔는데 수정시 api의 res data를 사용할 일이 생기니 setState내에서는 async await 사용이 불가능해서 질문드립니다... 바보같은 저에게 단비 같은 가르침을 내려주세요..
답변 1
스무스하게 하시려면 외부 상태 라이브러리나 useReducer를 쓰는게 좋습니다. 굳이 props로 넘기는 방식으로 만든다 그러면 아래와 같은 방향으로 구현하면 좋을듯 합니다.
1"use client";
2
3import {
4 Dispatch,
5 Fragment,
6 RefObject,
7 SetStateAction,
8 useRef,
9 useState,
10 useCallback,
11} from "react";
12
13type MyListData = RefObject<string[] | null>;
14
15const RenderingRef = () => {
16 const list = useRef<string[] | null>(["this", "is", "data"]);
17 const changeFunctionC = useCallback(
18 // 비동기 작업 아무거나
19 async (list: MyListData, setAction: Dispatch<SetStateAction<boolean>>) => {
20 let newList: string[] = [];
21 if (list.current) {
22 newList = [...list.current, "추가"];
23 }
24 //.. start await
25 list.current = newList;
26 console.log("🚀 ~ changeFunctionC ~ current:", list.current);
27 //.. end await
28
29 // 새로운 데이터 랜더링하도록 전파, 함수 변경과는 상관없음
30 setAction((prev) => !prev);
31 },
32 []
33 );
34
35 console.log("Parent Rendered");
36 return (
37 <div>
38 <h2>Ref를 사용해 보자</h2>
39 <YourCompB list={list} changeFunctionC={changeFunctionC} />
40 </div>
41 );
42};
43
44type YourCompBProps = {
45 list: MyListData;
46 changeFunctionC: (list: MyListData, setAction: Dispatch<SetStateAction<boolean>>) => void;
47};
48
49const YourCompB = ({ list, changeFunctionC }: YourCompBProps) => {
50 const [isChanged, setIsChanged] = useState(false);
51
52 console.log("값 바뀌었데~ , isChanged: ", isChanged);
53 console.log("Child Rendered");
54 if (!list.current || list.current.length === 0)
55 return (
56 <>
57 <p>데이터 없어용~</p>
58 </>
59 );
60 return (
61 <>
62 {list.current.map((item, index) => {
63 return (
64 <Fragment key={index}>
65 <p className="text-white">{item}</p>
66 </Fragment>
67 );
68 })}
69 <button
70 onClick={() => {
71 changeFunctionC(list, setIsChanged);
72 }}
73 >
74 조작버튼
75 </button>
76 </>
77 );
78};
79
80export default RenderingRef;
포크코딩
별빛상단 단주 • 5월 5일
그냥 의사 코드 정도니까, 원래 사용 목적에 맞게 변경하셔야 합니다!
지금 가입하면 모든 질문의 답변을 볼 수 있어요!
현직자들의 명쾌한 답변을 얻을 수 있어요.
이미 회원이신가요?
커리어리 AI 봇
GPT가 달아주는 답변입니다.
5월 5일
다양한 방법이 있지만 보편적으로 사용되는 몇 가지 방법을 소개하겠습니다. 1. `useEffect`와 `useState`를 활용하는 방법: 함수 내에서 비동기 작업을 수행하고 결과를 상태로 설정하는 패턴입니다. 이 경우, 업데이트가 필요할 때마다 `useEffect`가 실행됩니다. ```jsx const [A, setA] = useState(null); useEffect(() => { const fetchData = async () => { const response = await apiCall(); setA(response.data); }; fetchData(); }, [C]); // C 의존성이 변경될 때 마다 useEffect 실행 ``` 2. `useReducer`와 `useEffect`를 활용하는 방법: 이는 더 복잡한 상태 로직을 관리하기 위해 사용되며, 비동기 작업을 수행한 후 리듀서를 사용하여 상태를 업데이트합니다. ```jsx const [state, dispatch] = useReducer(reducer, initialState); useEffect(() => { const fetchData = async () => { dispatch({ type: 'FETCH_INIT' }); try { const response = await apiCall(); dispatch({ type: 'FETCH_SUCCESS', payload: response.data }); } catch (error) { dispatch({ type: 'FETCH_ERROR' }); } }; fetchData(); }, [C]); // C의 변화에 따라 useEffect 실행 ``` 3. 혹은 `React Query` 라이브러리와 같이 데이터 가져오는 것을 추상화하는 도구를 사용하는 방법도 있습니다. 이렇게 하면 컴포넌트 자체에서 비동기 로직을 처리할 필요가 없어집니다. ```jsx const queryInfo = useQuery('fetchData', () => fetch('/api/data'), { refetchOnWindowFocus: false, }); ``` 이 중에서 가장 적합한 방법을 선택하시면 될 것 같습니다. 작업의 복잡성, 프로젝트의 규모 등에 따라 가장 적합한 방법이 다를 수 있습니다.
지금 가입하면 모든 질문의 답변을 볼 수 있어요!