javascriptreactjsreact-nativenative-base

Image URLs pulled from database won't render after initial view in React Native application


So I've created a view in React Native (Work.js) that pulls portfolio information from a database (Supabase) and then loops through that returned work object and loads the data into a card-style custom component called WorkTile.js.

Work.js

import React, { useEffect, useState, useRef } from "react";
import {Text, Flex, Button, Center, Heading, VStack, ScrollView } from "native-base";
import supabase from "../supabase";
import WorkTile from "../components/WorkTile";
import Bowl from "../components/Bowl";

const Work = () => {
    const [works, setWork] = useState([]);
    const componentMounted = useRef(true);
    
    useEffect(() => {
        const fetchWork = async () => {
            const {data, error} = await supabase.from('work').select('*').order('featured', {ascending: false}); //.eq('type', '3D')
            
            if (error) {
                console.log('error', error);
            } else {
                setWork(data);
            }
        };
        if (componentMounted.current) {
            fetchWork();
        }

        return () => {
            componentMounted.current = false; 

        };
    }, []);

    return ( 
        <ScrollView h={"100%"} w={[400, 480, 640]} style={{ overflowx: "hidden" }}>
            <Bowl />
            <VStack pb={5} pt={0} mt={-200}  justifyContent={"space-between"}>
                <Heading mt={headings.mt} mb={headings.mb} pb={headings.pb} size={headings.size} borderBottomWidth={headings.bbw} borderBottomColor={headings.bbc} alignSelf={"flex-start"}>
                    Work
                </Heading>
                <Text fontSize={16} textAlign={"justify"}>Hello! My name is Jamie and I'm full stack web and app developer based outta Richmond, VA. In my years in marketing I've worn a lot of hats, including designer, developer, systems engineer, photographer, videogropher, project manager, product manager, and solutions architect and I love every minute of it! When I'm not online, you can find me on my bike, on my drumset, or making something on the stove top.</Text>            
            </VStack>      

            {/* Work Component */}
            <Center>
                <Flex flex={1} flexWrap={"wrap"} flexDirection={"row"} justifyContent={["center", "center", "space-between"]} >
                    {works.map((work, index) => (  
                        <WorkTile key={work.id} data={work} />
                    ))}
                </Flex>
            </Center>

            <Center>
                <Button mt={12} alignSelf="center" onPress={() => navigation.dispatch( CommonActions.navigate({ name: 'Work',  params: { cameFrom: 'Home' } } ) ) } >
                    Check out my resume ---
                </Button>
            </Center>

            <Center mt={8} mb={6}><Text fontSize={12} color={"warmGray.500"}>© {new Date().getFullYear()} Jamie Taylor. All rights reserved.</Text></Center>

        </ScrollView>
    );
}
 
export default Work;

WorkTile.js

import {Text, AspectRatio, Stack, Pressable, Heading } from "native-base";
import { Image } from "react-native";

function WorkTile({data}) {  
    return ( 
        <Pressable mt={5} shadow="2" rounded="lg" w={{ base: 96, md: 72, lg: 48 }} 
            _light={{ bg: "coolGray.50" }} _dark={{ bg: "gray.800" }} overflow={"hidden"}>
            <AspectRatio 
                ratio= {{ 
                    base: 16/9,
                    md: 16/9
                }} height= {{
                    base: 20,
                    md: 20
                }} >
                <Image key={data.id} resizeMode="cover" source={{
                    uri: data.imageFull
                }} alt={data.blurb} />
            </AspectRatio>
            <Text bold position="absolute" color="coolGray.50" top="0" m={3} mt={2}>
                {data.type.toUpperCase()}
            </Text>                       
            <Stack space="2" p="4">
                {/* <Text color="gray.400">{data.created_at}</Text> */}
                <Heading size={"md"} fontWeight="medium" isTruncated>
                    {data.name}
                </Heading>
                <Text isTruncated noOfLines={[2,4,4]}>
                    {data.blurb}
                </Text>
            </Stack>
        </Pressable>
    );
}

export default WorkTile;

The issue I'm having is that everything loads fine the first time, however after loading another view and coming back, all the text pulled from the database is there, however the images fail to load (see screenshots below). The issue persists regardless of Android, iOS, or web. I'm not getting any errors and I've tried a number of things from using useState, to using AsyncStorage, different Image components, etc. I notice that when I log the URLs used (data.imageFull) in WorkTile.js, they also only get logged to the console on initial load. I cannot figure out what I'm missing! Any help would be very much appreciated. Thanks in advance!

Initial Load:

Initial Load

Subsequent Views:

enter image description here


Solution

  • Problem was solved per @user18309290's comment. It seems that, despite pulling the code directly from the official NativeBase docs, AspectRation wrapping my Image component without a specified width and height on the Image, was not allowing my images to rerender.