๐Ÿ’ป[React Native] Navigation, Axios+useFocusEffect

ํ˜ฑยท2023๋…„ 1์›” 23์ผ

๐Ÿ“Œ Navigation

โœ”๏ธ ์„ค์น˜

ReactNavigation ํ™ˆํŽ˜์ด์ง€
ํ•„์š”ํ•œ Package ์„ค์น˜ ํ›„ (์•ˆ๋“œ๋กœ์ด๋“œ๋Š” MainActivity์—์„œ

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(null);
}

๋˜ํ•œ ๋ณต์‚ฌ ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

โœ”๏ธ ํ™œ์šฉ

๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฒฝ๋กœ ์Šคํฌ๋ฆฐ: BoxOffice page-> ํ•˜๋‚˜์˜ ์˜ํ™” ํด๋ฆญ -> MovieDetail page -> ๊ฐ๋… ๋˜๋Š” ๋ฐฐ์šฐ ํด๋ฆญ -> ๊ฐ๋…, ๋ฐฐ์šฐ์˜ ๋””ํ…Œ์ผํ•œ page

DefaultStackNavigator.js

import React from 'react';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import BoxOffice from '../screens/BoxOffice';
import MovieDetail from '../screens/MovieDetail';
import SearchResult from '../screens/SearchResult';

const Stack = createNativeStackNavigator();

export default function DefaultStackNavigator() {
  retrun(
    <>
      <Stack.Navigator>
        <Stack.Screen name={'BoxOffice'} component={BoxOffice} />
        <Stack.Screen name={'MovieDetail'} component={MovieDetail} />
        <Stack.Screen name={'SearchResult'} component={SearchResult} />
      </Stack.Navigator>
    </>,
  );
}

๊ฐ screen์— ๋Œ€ํ•œ StackNavigator๋ฅผ ์„ค์ •ํ•˜๊ณ , ์ด๋ฅผ component๋กœ ๋ฌถ์Œ
์ดํ›„ ๋ฌถ์€ RootController state๋ฅผ App.js์— ์ถ”๊ฐ€

export default function RootController() {
  return (
    <NavigationContainer>
      <DefaultStackNavigator />
    </NavigationContainer>
  );
}

โœ”๏ธ๊ฐ ์Šคํฌ๋ฆฐ ๋ณ„ ํ™œ์šฉ

BoxOffice.js

import React, {useEffect} from 'react';
import BoxOfficeItem from '../components/BoxOfficeItem';
import axios from 'a xios';

export default function BoxOffice({navigation}) {
  const [ranks, setRanks] = useState((initialState = []));
  useEffect(
    (effect = () => {
      const url =
        'https://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json';
      axios.get(
        url,
        (config = {
          params: {
            key: 'bb4881b8d562d9187648f76284e6f14c',
            targetDt: '20220222',
          },
        }).then(res => {
          setRanks(res.data?.boxOfficeResult?.dailyBoxOfficeList || []);
        }),
      );
    }),
    (deps = []),
  );
  return (
    <>
      {ranks.map(item => (
        <BoxOfficeItem navigation={navigation} key={item.rnum} data={item} />
      ))}
    </>
  );
}

BoxOfficeItem.js

import {useNavigation} from '@react-navigation/native';
import React, {useCallback} from 'react';
import {Pressable} from 'react-native';
import Paragraph from './ui/Paragraph';
import styled from 'styled-components';

const Container = styled.View`
  padding: 11px;
`;

export default function BoxOfficeItem({data}) {
  const navigation = useNavigation();
  let intenIcon = 'โบ';
  const parsedRankInten = parseInt(data.rankInten, {radix: 10});
  if (parsedRankInten < 0) {
    intenIcon = '๐Ÿ”ฝ';
  } else if (parsedRankInten > 0) {
    intenIcon = '๐Ÿ”ผ';
  }

  const navigateMovieDetail = useCallback(
    ((callback = () => {
      navigation.navigate('MovieDetail', {movieCd: data.movieCd});
    }),
    (deps = [navigation, data])),
  );

  return (
    <Pressable onPress={navigateMovieDetail}>
      <Container>
        <Row>
          <Paragraph>
            <Paragraph>{data.rank}</Paragraph>
            <Paragraph>
              {intenIcon} {data.rankInten}
            </Paragraph>
            <Paragraph>{data.movieNm}</Paragraph>
            <Paragraph>{data.rankOldAndNew === 'NEW' ? '๐Ÿ†•' : ''}</Paragraph>
          </Paragraph>
        </Row>
      </Container>
    </Pressable>
  );
}

๊ฐ ์•„์ดํ…œ์— ํ•ด๋‹นํ•˜๋Š” BoxOfficeItem.js์—์„œ MovieDetailํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก

  const navigateMovieDetail = useCallback(
    ((callback = () => {
      navigation.navigate('MovieDetail', {movieCd: data.movieCd});
    }),
    (deps = [navigation, data])),
  );

<Pressable onPress={navigateMovieDetail}> ์ฒ˜๋ฆฌ,
navigation Hook ๋งŒ๋“ค์–ด ์ฒ˜๋ฆฌ

MovieDetail.js

import {useFocusEffect, useRoute} from '@react-navigation/native';
import React, {useCallback, useEffect, useState} from 'react';
import {ActivityIndicator, Pressable} from 'react-native';
import Row from '../components/Row';
import Paragraph from '../components/ui/Paragraph';
import axios from 'axios';

export default function MovieDetail({route, navigation}) {
  const [detail, setDetail] = useState((initialState = null));
  useFocusEffect(
    useCallback(
      (callback = () => {
        const url =
          'https://www.kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieInfo.json';
        axios.get(
          url,
          (config = {
            params: {
              key: 'bb4881b8d562d9187648f76284e6f14c',
              movieCd: route.params.movieCd,
            },
          })
            .then(res => setDetail(res.data.movieInfoResult.movieInfo))
            .catch(console.warn),
        );
      }),
      (deps = []),
    ),
  );
  if (!detail) return <ActivityIndicator />; //๋กœ๋”ฉ์ด ๋Œ์•„๊ฐ€๋Š” ํ‘œ์‹œ
  return (
    <>
      <Row>
        <Paragraph>์˜ํ™”๋ช… : {detail.movieNm} </Paragraph>
      </Row>

      <Row>
        <Paragraph>์ƒ์˜์‹œ๊ฐ„ : {detail.showTm}๋ถ„ </Paragraph>
      </Row>
      <Row>
        <Paragraph>๊ฐœ๋ด‰์ผ : {detail.openDt} </Paragraph>
      </Row>
      <Row>
        <Paragraph>
          ๊ฐ๋…:
          {detail.directors.map(director => (
            <Link
              key={director.peopleNm}
              onPress={() => {
                navigation.navigate('SearchResult', {
                  peopleNm: director.peopleNm,
                });
              }}>
              {director.peopleNm}
            </Link>
          ))}
        </Paragraph>
      </Row>
      <Row>
        <Paragraph>
          ์ถœ์—ฐ:
          {detail.actors.map(actor => (
             <Link
              key={actor.peopleNm}
              onPress={() => {
                navigation.navigate('SearchResult', {
                  peopleNm: actor.peopleNm});
              }}>
              {actor.peopleNm}
            </Link>
          ))}
        </Paragraph>
      </Row>
    </>
  );
}

SearchResult.js

import React, {useCallback} from 'react';
import {useFocusEffect} from '@react-navigation/native';
import axios from 'axios';
import {FlatList, Pressable} from 'react-native';
import Paragraph from '../components/ui/Paragraph';

export default function SearchResult() {
  const [list, setList] = useState((initialState = []));
  useFocusEffect(
    useCallback(
      (callback = () => {
        const url =
          'https://www.kobis.or.kr/kobisopenapi/webservice/rest/people/searchPeopleList.json';
        axios.get(
          url,
          (config = {
            params: {
              key: 'bb4881b8d562d9187648f76284e6f14c',
              peopleNm: route.params.peopleNm,
            },
          })
            .then(res => setList(res.data.peopleListResultpeopleList))
            .catch(console.warn),
        );
      }),
      (deps = []),
    ),
  );
  return (
    <FlatList
      data={list}
      keyExtractor={item => item.peopleCd}
      renderItem={data => (
        <Pressable onPress={() => {}}>
          <Paragraph>
            {data.item.peopleNm}
            <Text>({data.item.filmoNames})</Text>
          </Paragraph>
        </Pressable>
      )}></FlatList>
  );
}

๋ฐฐ์šฐ, ๊ฐ๋…์˜ ์ด๋ฆ„์„ ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ€์•ผ ํ•˜๋ฏ€๋กœ, MovieDetail.js์—์„œ

onPress={() => {
                navigation.navigate('SearchResult', {
                  peopleNm: director.peopleNm,
                });

์œผ๋กœ ์ฒ˜๋ฆฌ

โœ”๏ธ ๊ฒฐ๋ก 

StackNavigator๋กœ ์„ค์ •(๋‹ค๋ฅธ navigation์€ ์ƒ๋‹จ ๋งํฌ ํ™•์ธ)
navigation.navigate('ํŽ˜์ด์ง€์ด๋ฆ„', {๋„˜๊ฒจ์ค„ params})๋กœ ์„ค์ •
๋˜๋Š”
navigation Hook์œผ๋กœ ์ฒ˜๋ฆฌ

Stack.Screen์—์„œ options={{headerShown: false}๋กœ stack์˜ header๋ฅผ ์—†์• ๊ณ  ui๋ฅผ ๊พธ๋ฐ€ ์ˆ˜ ์žˆ์Œ

๐Ÿ“Œ Axios+useFocusEffect

์•ฑ์—์„œ ๊ฐ screens๋Š” ์ „์˜ ํ™”๋ฉด์— ๋ฎ์–ด์“ฐ์—ฌ์ง€๋Š” ๊ฒƒ์ด๋ฏ€๋กœ, useEffect๋กœ๋Š” ์ƒํƒœ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Œ ๋”ฐ๋ผ์„œ ๊ฐ ์Šคํฌ๋ฆฐ์„ ๋ฐ”๋ผ๋ณด๋Š” ์‹œ์ ์œผ๋กœ ์„ค์ •: useFocusEffect
axios ํ†ต์‹ ์€ get-> ์ •๋ณด๋ฅผ ๋ฐ›์„ ๋•Œ ํ•ด๋‹นํ•˜๋Š” ๋งํฌ(url, https๋กœ ์ฒ˜๋ฆฌ), config์—์„œ ๊ฐ parms๋ฅผ ์š”๊ตฌ์‚ฌํ•ญ๋Œ€๋กœ ์„ค์ •ํ•˜์—ฌ ์ •๋ณด๋ฅผ ๋ฐ›์Œ

profile
new blog: https://hae0-02ni.tistory.com/

0๊ฐœ์˜ ๋Œ“๊ธ€