개발자

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

2023년 11월 27일조회 349

안녕하세요! 이번에 팔로우 추천 목록을 불러오는 것을 만드는 중인데 문제가 생겨서 질문 남깁니다. 원하는 결과대로라면 내가 팔로우 한 사람들을 불러온 후, 그 사람들의 팔로잉 리스트를 불러오고, 조건에 충족 한다면 저의 추천 팔로우 리스트에 포함시키는 것입니다. 하지만 결과가 저 자신이 팔로우 추천으로 뜨더라구요 ....ㅠㅠ 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.

1
2
3
4
for (const item of myFollowList) {
  let list = await getRecFollowingList(item.accountname);
  // blah blah..
}
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
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
// 1. getRecFollowingList.js 파일의 파일명과 내부의 함수명을 변경할 것을 
//    추천드립니다. 
//    getRecFollowingList.js -> getFollowingList.js
//    getRecFollowingList -> getFollowingList
//
//    ** 이유: 단순히 following list를 불러오는 것인데, rec를 붙여서 
//    전체적인 추천 following을 불러오는 부분과 혼돈이 발생할 여지가 있고 
//    코드의 이해가 어려워집니다.

const [allDerivedRecFollowingList, setAllDerivedRecFollowingList] = useState([])
// 2. 훅으로 상태 관리는 렌더링에 꼭 필요한 경우에 최소한만 사용할 것을
//     추천드립니다. 나중에 단순 myFollowList도 렌더링에 포함된다면
//     두 개다 하셔야 되는 건 맞습니다.

useEffect(() => {
  async function getAllDerivedRecFollowingList() {
    const duplicatedFollowSet= new Set();
    const seen = new Set();
    
    const myFollowingList = await getFollowingList(myAccountName);
    
    // 3. myFollowList를 여기서 바로 활용해 두 번째 useEffect에 있던 부분의 
    //     코드를 작성합니다. 여기서는 크게 상관없는 것 같기도 하나 김하림님이 
    //     언급해 주신 것처럼 뭔가를 순차적으로 페치해 와야할 때는 forEach를
    //     사용하지 않는 것이 좋습니다. 일반적인 for 블락으로 처리 하시거나 
    //     Promise.All()을 사용하시는 것이 좋습니다. forEach의 경우 에러없이 
    //     작동하기 때문에 순서 꼬이면 나중에 오류를 찾기가 더 어렵고
    //    시간이 걸리게 됩니다.

      for (const myFollowingItem of myFollowingList) {
        let derivedFollowingList = await getFollowingList(myFollowingItem.accountName);
       
    ...
     }
    
    setAllDerivedRecFollowingList([...duplicatedFollowSet])
  }
  
  getAllDerivedRecFollowingList()
}, [])
...
// 4. allDerivedRecFollowingList 를 렌더링합니다. 
//     (처음에 질문하실 때 작성하신 부분과 동일하게 렌더링 처리)
//
// 5. .then()을 사용하는 하는 건 생각해 보니 할 수는 있는데 비동기로 
//      처리해야하는 반복문이 있어 좀 복잡해지는 것 같습니다.
//
// 6. useEffect 부분이 길어지니 가독성을 위해 별도의 라이브러리 파일로 
//      빼고 import하는 것도 괜찮은 것 같습니다.
//
// ** 더 참고할 자료: [JS] 반복문 안에서의 비동기 함수 사용
//                               (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일

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

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

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

또는

이미 회원이신가요?

목록으로
키워드로 질문 모아보기

실무, 커리어 고민이 있다면

새로운 질문 올리기

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