로메오의 블로그

[React Native] Redux toolkit & Network call 본문

Frontend/React

[React Native] Redux toolkit & Network call

romeoh 2022. 11. 9. 16:27
반응형

React 목록

https://randomuser.me/documentation#pagination

Api 더미 데이터는 위 사이트에서 가져옵니다.

 

 

App.tsx

import React from 'react';
import {SafeAreaView, StatusBar} from 'react-native';
import {Provider as ReduxProvider} from 'react-redux';
import UserList from './UserList';
import store from './store';

const App = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ReduxProvider store={store}>
          <UserList />
        </ReduxProvider>
      </SafeAreaView>
    </>
  );
};

export default App;

 

 

 

 

 

store.ts

import {combineReducers, configureStore} from '@reduxjs/toolkit';
import userListSlice from './userListSlice';

const rootReducer = combineReducers({
  userList: userListSlice,
});

export type RootState = ReturnType<typeof rootReducer>;

const store = configureStore({
  reducer: rootReducer,
});

export default store;

 

 

 

 

 

apiClient.ts

import {User} from './userListSlice';

type ResponseKind = 'success' | 'failure';

type NetworkResponse<T> = {
  kind: ResponseKind;
  body?: T;
};

export const fetchUsers = async (
  page: number,
  count: number,
): Promise<NetworkResponse<User[]>> => {
  const response = await fetch(
    `https://randomuser.me/api/?page=${page}&results=${count}`,
    {
      method: 'GET',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
    },
  );
  if (response.ok) {
    const json = await response.json();
    return {
      kind: 'success',
      body: json.results,
    };
  } else {
    return {
      kind: 'failure',
    };
  }
};

 

 

 

 

 

 

userListSlice.ts

import {createAsyncThunk, createSlice} from '@reduxjs/toolkit';
import * as apiClient from './apiClient';

export type User = {
  name: {
    first: string;
  };
  picture: {
    thumbnail: string;
  };
};

export type UserListState = {
  users: User[];
  loading: boolean;
  error?: boolean;
  nextPage: number;
};

const initialState: UserListState = {
  users: [],
  loading: false,
  error: true,
  nextPage: 1,
};

/**
 * Redux Toolkit 비동기 처리
 */
export const fetchUsers = createAsyncThunk<{users: User[]}, {page: number}>(
  'fetchUsers',
  async ({page}) => {
    const response = await apiClient.fetchUsers(page, 10);
    if (response.kind === 'success') {
      return {
        users: response.body ?? [],
      };
    } else {
      throw 'Error fetching users';
    }
  },
);

/**
 * thunk slice
 */
const userListSlice = createSlice({
  name: 'userList',
  initialState: initialState,
  reducers: {},
  extraReducers: builder => {
    builder
      .addCase(fetchUsers.pending, state => {
        state.loading = true;
        state.error = undefined;
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.nextPage += 1;
        state.users = state.users.concat(action.payload.users);
        state.loading = false;
      })
      .addCase(fetchUsers.rejected, state => {
        state.error = true;
        state.loading = false;
      });
  },
});

export default userListSlice.reducer;

Redux Toolkit 비동기 처리는 아래 사이트에서 확인하세요.

https://redux-toolkit.js.org/api/createAsyncThunk

https://velog.io/@raejoonee/createAsyncThunk

 

 

 

 

 

 

UserList.tsx

import React, {FunctionComponent, useEffect} from 'react';
import {FlatList, StyleSheet, Text, View, Image} from 'react-native';
import {useDispatch, useSelector} from 'react-redux';
import {RootState} from './store';
import {fetchUsers, User} from './userListSlice';

const UserList: FunctionComponent = () => {
  const dispatch = useDispatch();

  const screenState = useSelector((state: RootState) => state.userList);

  useEffect(() => {
    dispatch(fetchUsers({page: 1}));
  }, []);

  const handleOnEndReached = () => {
    if (!screenState.loading) {
      dispatch(fetchUsers({page: screenState.nextPage}));
    }
  };

  return (
    <>
      {screenState.loading && <Text>LOADING</Text>}
      {screenState.error && <Text>ERROR</Text>}
      {!screenState.loading && !screenState.error && <Text>DEFAULT</Text>}
      <FlatList
        data={screenState.users}
        keyExtractor={(_, index) => {
          return index.toString();
        }}
        renderItem={({item}) => <UserListItem user={item} />}
        onEndReached={handleOnEndReached}
      />
    </>
  );
};

const UserListItem: FunctionComponent<{user: User}> = ({user}) => {
  return (
    <View style={style.container}>
      <Image style={style.thumbnail} source={{uri: user.picture.thumbnail}} />
      <Text style={style.nameText}>{user.name.first}</Text>
    </View>
  );
};

const style = StyleSheet.create({
  container: {
    flexDirection: 'row',
    padding: 15,
    alignItems: 'center',
  },
  nameText: {
    padding: 15,
  },
  thumbnail: {
    width: 50,
    height: 50,
    borderRadius: 25,
    borderColor: 'purple',
    borderWidth: 3,
  },
});

export default UserList;

 

 

 

 

 

 

React 목록

반응형

'Frontend > React' 카테고리의 다른 글

[React Native] 디버그 [Chrome DevTools & Safari]  (0) 2022.11.15
[React Native] Redux toolkit & Todo App  (2) 2022.11.12
[React Native] Redux toolkit  (0) 2022.11.08
[React Native] Draggable FlatList  (0) 2022.10.24
[React Native] props  (0) 2022.10.20
Comments