개발자

리액트 비동기 문제일까요 ㅠㅠ?

2023년 11월 27일조회 341

안녕하세요! 이번에 팔로우 추천 목록을 불러오는 것을 만드는 중인데 문제가 생겨서 질문 남깁니다. 원하는 결과대로라면 내가 팔로우 한 사람들을 불러온 후, 그 사람들의 팔로잉 리스트를 불러오고, 조건에 충족 한다면 저의 추천 팔로우 리스트에 포함시키는 것입니다. 하지만 결과가 저 자신이 팔로우 추천으로 뜨더라구요 ....ㅠㅠ getRecFollowingList의 결과를 콘솔로 찍었을 때 첫 번째, 두 번째 useEffect에서 모두 저 자신의 팔로잉 리스트를 불러옵니다.... ㅠㅠ 제가 생각했을 때, 첫 번째 useEffect에서 setMyFollowList한 것이 아직 반영되지 않아서 두 번째 myFollowList가 forEach를 못 도는 건지... 아니면 getRecFollowingList가 통신이 제대로 안되는건지 모르겠습니다.

이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.
profile picture
익명님의 질문

답변 3

김하림님의 프로필 사진

30번 째 줄 myFollowList.forEach 콜백 함수에 async/await를 쓰신 게 문제의 원인으로 추정됩니다. forEach는 프로미스 응답을 기다리지 않기 때문에, 예상한 결과와 다른 값이 나올 수 있습니다. 로직을 for..of로 변경해서 작성해보세요. 예시 코드처럼요. 참고: MDN - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach > forEach() expects a synchronous function — it does not wait for promises. Make sure you are aware of the implications while using promises (or async functions) as forEach callbacks.

1for (const item of myFollowList) {
2  let list = await getRecFollowingList(item.accountname);
3  // blah blah..
4}
profile picture

익명

작성자

2023년 11월 29일

안녕하세요! 답변 주셔서 감사합니다. ㅠㅠ 말씀하신 것과 같이 고쳐보았는데 이전과 똑같은 결과가 나타나서 혹시 제가 고친게 잘못된 것인지 확인해주실 수 있을까요? useEffect(()=>{ Rec(); }, [myFollowList]); const Rec= async()=> { const duplicatedFollowSet= new Set(); const seen= new Set(); for (const item of myFollowList) { let list= await getRecFollowingList(item.accountname); ... } 이 부분에서 async를 쓰려고 Rec이라는 함수를 만들어 async를 써주었고, useEffect에 넣어주었습니다..!!

박정웅님의 프로필 사진

myFollowList값을 useState로 넣는 방법 말고, useEffect를 하나만 만들고 그 안에 나눠져 있는 코드들을 둘 다 넣어서 `async`로 myFollowList 페치해온 값을 넘기거나, `.then(followers => ...` 로 값을 넘겨서 처리하면 되지않을까요? 그리고 제 생각에는 첫 번째, 두 번째 모두 자신의 팔로우를 불러오는 것이 아니라 첫 번째가 콘솔에 두 번 찍히는 것 같습니다. - 첫 번째 useEffect conslole.log(">> my follow list:", list); - 두 번째 useEffect console.log(">> recommended follow list:", list); 이렇게 앞에 명확하게 표시하면 확인하는데 더 도움이 되시지 않을까 싶습니다.

profile picture

익명

작성자

2023년 12월 01일

안녕하세요! 답변 주셔서 정말 감사합니다. 말씀해주신대로 콘솔을 찍었더니 보기에도 명확하고 편했습니다! 혹시 처음에 useEffect를 하나로 만들고 난 뒤에 myFollowList 값을 넘기는 방법에 대해서 말씀해주셨는데 혹시 조금만 더 자세하게 설명해주실 수 있을까요 🥲?!

박정웅님의 프로필 사진

제가 전체적인 코드 배경을 잘 몰라서, 잘못 이해하고 있을 수도 있습니다. 그리 복잡하지 않은 단순한 내용인데 설명이 장황해진 것 같아 죄송합니다. ** 간단 하게 말씀드리면 3번 설명 자리에 그냥 두번째 useEffect 에 있던 코드를 연결해서 작업하는 것입니다.

1// 1. getRecFollowingList.js 파일의 파일명과 내부의 함수명을 변경할 것을 
2//    추천드립니다. 
3//    getRecFollowingList.js -> getFollowingList.js
4//    getRecFollowingList -> getFollowingList
5//
6//    ** 이유: 단순히 following list를 불러오는 것인데, rec를 붙여서 
7//    전체적인 추천 following을 불러오는 부분과 혼돈이 발생할 여지가 있고 
8//    코드의 이해가 어려워집니다.
9
10const [allDerivedRecFollowingList, setAllDerivedRecFollowingList] = useState([])
11// 2. 훅으로 상태 관리는 렌더링에 꼭 필요한 경우에 최소한만 사용할 것을
12//     추천드립니다. 나중에 단순 myFollowList도 렌더링에 포함된다면
13//     두 개다 하셔야 되는 건 맞습니다.
14
15useEffect(() => {
16  async function getAllDerivedRecFollowingList() {
17    const duplicatedFollowSet= new Set();
18    const seen = new Set();
19    
20    const myFollowingList = await getFollowingList(myAccountName);
21    
22    // 3. myFollowList를 여기서 바로 활용해 두 번째 useEffect에 있던 부분의 
23    //     코드를 작성합니다. 여기서는 크게 상관없는 것 같기도 하나 김하림님이 
24    //     언급해 주신 것처럼 뭔가를 순차적으로 페치해 와야할 때는 forEach를
25    //     사용하지 않는 것이 좋습니다. 일반적인 for 블락으로 처리 하시거나 
26    //     Promise.All()을 사용하시는 것이 좋습니다. forEach의 경우 에러없이 
27    //     작동하기 때문에 순서 꼬이면 나중에 오류를 찾기가 더 어렵고
28    //    시간이 걸리게 됩니다.
29
30      for (const myFollowingItem of myFollowingList) {
31        let derivedFollowingList = await getFollowingList(myFollowingItem.accountName);
32       
33    ...
34     }
35    
36    setAllDerivedRecFollowingList([...duplicatedFollowSet])
37  }
38  
39  getAllDerivedRecFollowingList()
40}, [])
41...
42// 4. allDerivedRecFollowingList 를 렌더링합니다. 
43//     (처음에 질문하실 때 작성하신 부분과 동일하게 렌더링 처리)
44//
45// 5. .then()을 사용하는 하는 건 생각해 보니 할 수는 있는데 비동기로 
46//      처리해야하는 반복문이 있어 좀 복잡해지는 것 같습니다.
47//
48// 6. useEffect 부분이 길어지니 가독성을 위해 별도의 라이브러리 파일로 
49//      빼고 import하는 것도 괜찮은 것 같습니다.
50//
51// ** 더 참고할 자료: [JS] 반복문 안에서의 비동기 함수 사용
52//                               (https://sjh9708.tistory.com/25)
profile picture

익명

작성자

2023년 12월 02일

답변주셔셔 감사합니다!! 주석으로 친절하게 설명까지 해주신 덕분에 잘 이해가 됐습니다.!! 말씀해주신대로 코드를 수정했습니다. 코드 가독성 문제도 해결이 되어서 너무 편안해요! 하지만 첫 번째 컴파일 후 결과를 봤을 때에는 “추천 팔로우가 없습니다.” 라고 뜨고 새로고침 했을 때는 “ 저 자신이 팔로우“로 뜨고, 코드에 주석을 단다거나 결과에 관련없이 수정을 했을 경우는 ”추천 팔로우“가 제대로 나타납니다 ㅜㅜ 어떤것이 문제인지 한참을 고민하다가 답변을 남겨욥 ㅠㅠ 설명이 장황한데 혹시 보시게 된다면 답장 한 번만 부탁드릴게요 ..!! 늦은시간에 정말 죄송합니다. 편안한 밤 보내세요 :)

박정웅님의 프로필 사진

박정웅

프리랜서 개발자2023년 12월 03일

도움이 되셨다니 다행입니다.^^ 댓글 달아 주신 부분에서 ... "코드에 주석을 단다거나 결과에 관련없이 수정을 했을 경우는 ”추천 팔로우“가 제대로 나타납니다" ... 이 부분이 잘 이해가 되지 않습니다. 말씀하신 "수정"이 어떤 부분인지 조금만 더 설명해 주시면 좋을 것 같아요. 혹시, 한 번이라도 성공하셨다면 그 성공할 때 수정하신 부분을 잘 보셔서 연구하는 것이 도움이 되실 것 같아요.

박정웅님의 프로필 사진

박정웅

프리랜서 개발자2023년 12월 03일

중요한 부분은 아닌 것 같지만, 중복체크를 하시니까 그냥 배열로 해도 되지 않을까요? const duplicatedFollowSet = [] duplicatedFollowSet.push(item)

profile picture

익명

작성자

2023년 12월 04일

알림이 안 떠서 지금 보았네요 ㅠㅠ 제가 설명을 잘 못드린 것 같아요 ㅎㅎ.. 계속 도움주셔서 정말 감사합니다. 정웅님 말씀대로 성공은 했으니 계속 고민해볼게요!! 감사합니다 좋은 하루 보내세요 ~! :)

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

AI 답변
커리어리 AI 봇 프로필 이미지

커리어리 AI 봇

GPT가 달아주는 답변입니다.

2023년 11월 27일

팔로우 추천 시스템을 구현하시려는 군요, 좋은 문제입니다! 질문에서 언급한 코드가 없어서 정확한 답변을 드리기는 어렵지만, 기술적인 문제 해결에 대해 일반적인 접근 방식을 제안드릴 수 있습니다. 1. 첫 번째로 여러분이 가정한 것처럼 `setMyFollowList`로 상태를 갱신하는 것이 첫 번째 `useEffect`에서 완료되기 전에 두 번째 `useEffect`가 실행되는 경우를 확인해 볼 수 있습니다. React의 상태 설정 함수는 비동기적으로 동작하므로 이것이 원인일 가능성이 있습니다. 이를 해결하기 위해선 첫 번째 useEffect 안에서 fetch 작업을 마친 후 setMyFollowList를 호출하고, 그 다음에 getRecFollowingList 같은 함수를 호출하는 로직을 만들면 됩니다. 2. 두 번째로는 `getRecFollowingList` 통신 자체에 문제가 있는지 확인할 필요가 있습니다. 서버에서 올바른 데이터를 반환하고 있는지, 그리고 이 데이터가 올바르게 처리되고 있는지 확인해봅니다. 3. 세 번째로는 팔로우 추천 리스트를 생성하는 로직 자체에 문제가 있는지 확인합니다. 예상하지 못한 조건에 따라 자신을 추천 리스트에 포함시키는 건 아닌지 확인해봅니다. 위 사항들을 체크하면서 디버깅을 해보시면 문제의 원인을 좀 더 쉽게 찾을 수 있을 것입니다.

목록으로

지금 가입하면 모든 질문의 답변을 볼 수 있어요!