Commit 75dcafa6 authored by ErlendHer's avatar ErlendHer
Browse files

#4 Load movies dynamically.

parent 70676df2
import React, { useEffect, useState } from 'react';
import { FlatList, Image, StyleSheet, View, Text } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { fetchMovies } from '../store/ducks/movies/actions';
import { FetchMovieParams, MovieEntity } from '../store/ducks/movies/types';
import { ApplicationState } from '../store/interface';
const baseQuery: FetchMovieParams = {
perPage: 10,
page: 0,
orderBy: 'title',
order: 'desc',
filters: {
title: 'Al',
},
};
const MovieTable = ({ path }: { path: string }): JSX.Element => {
const dispatch = useDispatch();
const { data, documentCount, loading, error } = useSelector(
({ movies }: ApplicationState) => movies
);
const [movies, setMovies] = useState<MovieEntity[]>([]);
const [prevPageLoaded, setPageLoaded] = useState(0);
const fetchByPage = (page: number) => {
dispatch(fetchMovies({ ...baseQuery, page }));
};
// Fetch movies on mount
useEffect(() => {
dispatch(fetchMovies(baseQuery));
setPageLoaded(baseQuery.page);
}, []);
// Fetch movies on page change
useEffect(() => {
if (!error && !loading) {
setMovies([...movies, ...data]);
}
}, [data]);
return (
<FlatList
contentContainerStyle={{
flex: 1,
flexDirection: 'column',
height: '100%',
width: '100%',
}}
data={movies}
keyExtractor={(movie) => movie.id.toString()}
onEndReached={({ distanceFromEnd }) => {
// Prevent bug where onEndReached is called multiple times
if (distanceFromEnd < 0) return;
// Prevent fetching if all movies are loaded
if (prevPageLoaded + 1 === documentCount / baseQuery.perPage) return;
fetchByPage(prevPageLoaded + 1);
setPageLoaded(prevPageLoaded + 1);
}}
onEndReachedThreshold={0.5}
initialNumToRender={baseQuery.perPage}
renderItem={({ item }) => (
<View>
<Text>{item.title}</Text>
<Image
source={{
uri: item.poster,
}}
style={styles.poster}
/>
</View>
)}
/>
);
};
const styles = StyleSheet.create({
poster: {
height: 100,
resizeMode: 'contain',
},
});
export default MovieTable;
......@@ -5,7 +5,11 @@
*/
import { FontAwesome } from '@expo/vector-icons';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native';
import {
NavigationContainer,
DefaultTheme,
DarkTheme,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import * as React from 'react';
import { ColorSchemeName, Pressable } from 'react-native';
......@@ -13,17 +17,27 @@ import { ColorSchemeName, Pressable } from 'react-native';
import Colors from '../constants/Colors';
import useColorScheme from '../hooks/useColorScheme';
import ModalScreen from '../screens/ModalScreen';
import MovieTableScreen from '../screens/MovieTableScreen';
import NotFoundScreen from '../screens/NotFoundScreen';
import TabOneScreen from '../screens/TabOneScreen';
import TabTwoScreen from '../screens/TabTwoScreen';
import { RootStackParamList, RootTabParamList, RootTabScreenProps } from '../types';
import {
RootStackParamList,
RootTabParamList,
RootTabScreenProps,
} from '../types';
import LinkingConfiguration from './LinkingConfiguration';
export default function Navigation({ colorScheme }: { colorScheme: ColorSchemeName }) {
export default function Navigation({
colorScheme,
}: {
colorScheme: ColorSchemeName;
}) {
return (
<NavigationContainer
linking={LinkingConfiguration}
theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}
>
<RootNavigator />
</NavigationContainer>
);
......@@ -38,8 +52,16 @@ const Stack = createNativeStackNavigator<RootStackParamList>();
function RootNavigator() {
return (
<Stack.Navigator>
<Stack.Screen name="Root" component={BottomTabNavigator} options={{ headerShown: false }} />
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
<Stack.Screen
name="Root"
component={BottomTabNavigator}
options={{ headerShown: false }}
/>
<Stack.Screen
name="NotFound"
component={NotFoundScreen}
options={{ title: 'Oops!' }}
/>
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="Modal" component={ModalScreen} />
</Stack.Group>
......@@ -61,7 +83,8 @@ function BottomTabNavigator() {
initialRouteName="TabOne"
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme].tint,
}}>
}}
>
<BottomTab.Screen
name="TabOne"
component={TabOneScreen}
......@@ -73,7 +96,8 @@ function BottomTabNavigator() {
onPress={() => navigation.navigate('Modal')}
style={({ pressed }) => ({
opacity: pressed ? 0.5 : 1,
})}>
})}
>
<FontAwesome
name="info-circle"
size={25}
......@@ -92,6 +116,14 @@ function BottomTabNavigator() {
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
}}
/>
<BottomTab.Screen
name="MovieTableTab"
component={MovieTableScreen}
options={{
title: 'Movie Table Tab',
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
}}
/>
</BottomTab.Navigator>
);
}
......
import * as React from 'react';
import { StyleSheet } from 'react-native';
import EditScreenInfo from '../components/EditScreenInfo';
import MovieTable from '../components/MovieTable';
import { Text, View } from '../components/Themed';
import { RootTabScreenProps } from '../types';
export default function MovieTableScreen({
navigation,
}: RootTabScreenProps<'MovieTableTab'>) {
return (
<View style={styles.container}>
<MovieTable path="/screens/TabOneScreen.tsx" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
separator: {
marginVertical: 30,
height: 1,
width: '80%',
},
});
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"jsx": "react",
"strict": true
}
}
......@@ -4,7 +4,10 @@
*/
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
import { CompositeScreenProps, NavigatorScreenParams } from '@react-navigation/native';
import {
CompositeScreenProps,
NavigatorScreenParams,
} from '@react-navigation/native';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
declare global {
......@@ -19,17 +22,17 @@ export type RootStackParamList = {
NotFound: undefined;
};
export type RootStackScreenProps<Screen extends keyof RootStackParamList> = NativeStackScreenProps<
RootStackParamList,
Screen
>;
export type RootStackScreenProps<Screen extends keyof RootStackParamList> =
NativeStackScreenProps<RootStackParamList, Screen>;
export type RootTabParamList = {
TabOne: undefined;
TabTwo: undefined;
MovieTableTab: undefined;
};
export type RootTabScreenProps<Screen extends keyof RootTabParamList> = CompositeScreenProps<
BottomTabScreenProps<RootTabParamList, Screen>,
NativeStackScreenProps<RootStackParamList>
>;
export type RootTabScreenProps<Screen extends keyof RootTabParamList> =
CompositeScreenProps<
BottomTabScreenProps<RootTabParamList, Screen>,
NativeStackScreenProps<RootStackParamList>
>;
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment