작성
·
166
0
const itemId = route.params ? route.params.id : route.route.params.id;
목록에서 위와 같이 아이디 값으로 상세 페이지로 들어가도록 했습니다.
useEffect(() => {
const geDetailData = async () => {
try {
const token = await EncryptedStorage.getItem('refreshToken');
const response = await axios.get(
__DEV__
? 'http://10.0.2.2:8888/api/deta/detail/' + itemId
: 'http://xxx.xxx.xxx.xxx:8888/api/data/detail/' + itemId,
{
headers: {
Authorization: token,
},
},
);
dispatch(
detailSlice.actions.setDetail({
id: response.data.id,
detail: response.data.detail,
nameList: response.data.nameList,
cityList: response.data.cityList,
}),
);
} catch (error) {}
};
if (isFocused) {
geDetailData();
}
}, [dispatch, isFocused, itemId]);
위와 같이 useEffect로 데이터를 불러오고, isFocused로 페이지에 접속할 때 마다 새로운 데이터를 가져오도록 했습니다.
return (
<ScrollView>
<View style={styles.wrapper}>
<View style={styles.boxZone}>
<View>
<FlatList
data={detail.nameList}
numColumns={3}
keyExtractor={item => item.id}
renderItem={renderNameList}
columnWrapperStyle={styles.row}
/>
</View>
</View>
</View>
<View style={styles.Wrapper}>
<FlatList
data={detail.cityList}
keyExtractor={item => item.id}
renderItem={renderCityList}
ListEmptyComponent={ListEmptyComponent}
/>
</View>
</ScrollView>
);
위와 같이 ScrollView 안에 FlatList를 두 개를 넣었습니다.
이렇게 구조를 잡은 이유는
상세 페이지에서 이름 목록과 시티 목록을 가져오기 위해서입니다.
그리고 상단에서는
const detail = useSelector((state: RootState) => state.detail);
위와 같이 useSelector로 데이터를 불러왔습니다.
그리고 renderNameList, renderCityList는 useCallback로 데이터를 불러와서 화면에 그리도록 작업을 했습니다.
실행을 해 보면 결과가 이상하게 나옵니다.
예를들어
게시글 목록이 111, 222 두 개가 있을경우
처음 111을 들어가면 정상적으로 나옵니다.
그런데 111을 들어갔다 목록으로 와서 222를 들어가면 111 의 상세 데이터가 보여집니다.
그 상태에서 다시 목록으로 가서 222를 들어가면 222의 데이터가 정상적으로 보여집니다.
이런식으로 어떤 상세 페이지를 들어가더라도 처음 한 번은 이전 데이터가 나오고, 다시 목록으로 갔다가 상세로 들어가면 정상적인 데이터가 나오는데 아무리 이리저리 찾아보고, 적용을 해 봐도 도저히 원인을 못찾겠네요.
if (isFocused) {
geDetailData();
}
isFocused를 사용해서 페이지 접근시 서버에서 데이터를 불러오도록 실행을 했는데, 처음 페이지에 접속할때는 정상적인 데이터가 안나옵니다.
답변 2
0
안녕하세요, 인프런 AI 인턴입니다.
인프러너 님의 상황에서 발생하는 문제는 상태 관리와 리액트 네이티브의 페이지 포커스 이벤트 처리와 관련이 있는 것으로 보입니다. isFocused
를 사용하여 페이지에 포커스 될 때 데이터를 가져오는 로직이 있지만, 어떤 경우에는 이전 페이지의 데이터가 남아 있는 상황이 발생하는 것으로 보입니다. 이러한 문제는 다음과 같은 요소들에 의해 영향을 받을 수 있습니다.
useEffect
내의 isFocused
와 itemId
를 의존성 배열에 포함시키는 것은 올바른 접근입니다. 하지만, 상태 업데이트 로직을 확인하고, 데이터를 불러오는 부분에서 의존성 배열에 포함된 변수들이 변경될 때마다 제대로 반응하는지 확인해야 합니다.isFocused
값이 제대로 업데이트 되고 있는지, 또한 해당 이벤트에 의존하는 로직이 적절하게 동작하고 있는지 검토합니다.올리신 코드와 설명만으로는 정확한 원인 파악이 어렵지만, 인프러너 님의 문제 해결에 도움이 될 수 있는 관련 답변을 몇 가지 추천드립니다.
AsyncStorage 비동기로 인한 undefined 문제
useEffect
와 useState
를 사용하여 비동기 데이터를 처리하는 방법과 관련된 질문에서는 비동기 요청 후 상태 업데이트가 바로 반영되지 않는 문제에 대한 해결책을 제시합니다. 이는 상세 페이지 데이터를 업데이트하는 과정에도 유용한 정보를 제공할 수 있습니다.비동기 작업과 상태 관리에 관련된 깊은 이해가 필요한 문제입니다. 위의 링크들을 참고하여 문제를 해결하는데 도움이 되었으면 합니다. Redux 상태 관리 로직에 대해서도 재검토하시는 것을 추천드립니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
0
지금 코드 구조는 화면 렌더링 후 useEffect에서 데이터불러오는 코드가 완료됩니다(비동기) 그래서 예전 데이터가 보였다가 다음번 접속 시에야 제대로 보이는 것 같네요.
111 -> 222 -> 111 이렇게 가보시면 데이터가
111 -> 111 -> 222 이렇게 보일 것 같습니다
그건 아닐거라 생각되긴 합니다. 어차피 await axios부분은 비동기라서 useEffect가 위에 있든 아래에 있든 useSelector 다음에 실행되거든요.
소스 구조상 순서대로 실행이 되서 useEffect가 먼저 실행되고 그 안에서 dispatch를 통해서 리덕스에 데이터가 저장이 되고, 저장된 데이터를 useSelector를 통해서 detail로 받아와서 화면에 뿌려주는 순서로 실행이 되는거 아닌가요??
그래서 useSelector 가 useEffect 보다 나중에 실행이 되어야 리덕스에 저장된 데이터가 axios를 통해서 최신 데이터로 업데이트가 되고, 그 데이터를 가져와서 화면에 뿌려주면 맞을거라고 생각을 하고 있는데.
그럼 제가 생각한 것이 잘못된 것일까요???
만약 제가 잘못 생각하고 있었던 것이라면 어떤식으로 잘못 생각을 하고 있었는지 모르겠네요.
function detail() {
const detail = useSelector((state: RootState) => state.detail);
useEffect(() => {
const geDetailData = async () => {
try {
const token = await EncryptedStorage.getItem('refreshToken');
const response = await axios.get(
__DEV__
? 'http://10.0.2.2:8888/api/deta/detail/' + itemId
: 'http://xxx.xxx.xxx.xxx:8888/api/data/detail/' + itemId,
{
headers: {
Authorization: token,
},
},
);
dispatch(
detailSlice.actions.setDetail({
id: response.data.id,
detail: response.data.detail,
nameList: response.data.nameList,
cityList: response.data.cityList,
}),
);
} catch (error) {}
};
if (isFocused) {
geDetailData();
}
}, [dispatch, isFocused, itemId]);
return "<View>...</View>"
}
export default detail;
위와같은 소스가 있다면 실행 순서가 맨 아래에 있는 detail 함수가 실행되고,
1. 첫 줄에 있는 detail이 리덕스에서 저장된 값을 가져오고
2. useEffect가 실행되고 그 안에서 async를 통해 비동기로 실행되면서 await으로 토큰 정보를 가져오고, await로 서버에서 데이터를 받아오도록 실행을 하고, (async, await은 비동기 함수라 async 다음에 await이 동작이 끝나면 그 다음 await이 실행되는식으로 진행)
dispatch로 리덕스의 스토어에 데이터를 저장한 후에
isFocused를 통해 getDetailData가 실행이 되고
마지막으로 View... 부분이 랜더링 되는 구조가 아닌가요??
그래도 useSelector가 위에 있으면 await을 통해 데이터를 받아오는것보다 먼저 실행이 되서 저장되어있던 값을 가져오지 않나요?
갑자기 머리가 복잡해 지네요.
혹시 제가 어떤 부분을 어떻게 잘못 알고 있었는지 알 수 있을까요?
useSelector 바로 아래 로그 1번
useEffect 바로 아래 로그 2번
dispatch 끝나는 부분 아래 로그3번
useEffect 바깥에서 로그4번
<View> 바로 위에 로그 5번으로 찍었는데
11111:
4444
5555(반복갯수만큼)
2222
1111
4444
5555(반복갯수만큼)
3333
이런 순서로 찍히네요.
로그 순서를 보니 어떤식으로 진행되는지 알겠네요.
그래서 useSelector 위치가 상관이 없다는 이야기인거네요..
근데 로그를 찍으면서 궁금한게..
2번 로그는 useEffect바로 아래넣어서 async 윗 부분에 로그가 찍히도록 했는데 useEffect는 랜더링이 완료된 후에 로그가 찍히네요..
그러면 화면 랜더링이 끝나고 난 후에 데이터를 불러온다는건데.. 화면을 그려준 후에 데이터가 적용이 되는거네요..(화면이 다 그려진 후에 데이터가 바뀌는게 이해가 좀 안가네요.)
그리고 1, 4, 5, 2번까지 로그 출력되고나서 다시 1, 4, 5번 로그가 찍히는데 왜 다시 반복이 되는지 모르겠네요.
이 부분을 useEffects 다음으로 내리고 테스트를 해 봤는데 정상적인 데이터가 불러와지네요.
useEffects로 랜더링을 하고 그 데이터를 slice안에 넣은 후 아래서 useSelector로 호출을 하면 정상적인 데이터가 불러와질 것으로 생각되서 그렇게 했는데 정상적으로 불러와 지네요.
흐름이 이런식으로 가는게 맞는거죠?