Search code examples
javascriptreact-nativeconditional-rendering

add a condition according to the presence of a database data


I have a list in which I want to add an image. Basically my code worked fine and the API database I use has unfortunately changed ... Some products in my database don't have an image so it gives me an error when I call the line in question... So, I want to create a condition: If there is an image for the product in question in the database, I want it to be displayed

Image source={{uri: URL + item.photo.1.url}}

Otherwise I want it to be a preset logo. <Image source={require('../../../assets/images/logo.png')}

I did it this way:

 <ListItem.Content style={{flexDirection: 'row', justifyContent: 'space-between'}}>
                        {item.photo !== null && item.photo > 0 ? (
                          <Image 
                            source={{uri: URL + item.photo._1_.url}}
                            style={{ width: 25, height: 25}}/> 
                        ) : (
                          <Image 
                            source={require('../../../assets/images/logo.png')}
                            style={{ width: 25, height: 25}}
                          />
                        )};
                        <ListItem.Title style={{width: '65%', fontSize: 16}}>{ ( item.name.length > 20 ) ? item.name.substring(0, 20) + ' ...'  :  item.name}</ListItem.Title>
                        <ListItem.Subtitle style={{ color: '#F78400', position: "absolute", bottom: 0, right: 0 }}>{item.cost}{i18n.t("products.money")}</ListItem.Subtitle>
                      </ListItem.Content>

But I have 2 errors:

undefined is not an object (evaluating 'item.photo.1.url')

[Unhandled promise rejection: Error: Text strings must be rendered within a component.]

To show you how the data looks :

screendata

And the full code of that screen :

export default class Products extends Component {
  constructor(props) {
    super(props);
      this.state = {
        productId: (props.route.params && props.route.params.productId ? props.route.params.productId : -1),
        listData: '',
        selectedId: '',
        setSelectedId: '',
        currentPage: 1,
        loadMoreVisible: true,
        loadMoreVisibleAtEnd: false,
        displayArray: []
      }
    };

  initListData = async () => {
    let list = await getProducts(1);
   
    if (list) {
      this.setState({
        displayArray: list,
        loadMoreVisible: (list.length >= 10 ? true : false), 
        currentPage: 2
      });
    }
  };

  setNewData = async (page) => {
    let list = await getProducts(parseInt(page));

    if (list) {
      this.setState({
        displayArray: this.state.displayArray.concat(list),
        loadMoreVisible: (list.length >= 10 ? true : false),
        loadMoreVisibleAtEnd: false,
        currentPage: parseInt(page)+1
      });
    }
  };

  loadMore() {
   this.setNewData(this.state.currentPage);
  }

  displayBtnLoadMore() {
    this.setState({
      loadMoreVisibleAtEnd: true
    });
  }

  async componentDidMount() {
    this.initListData();
  }

   render() {
  //console.log('url', URL );
  //console.log('displayArray', this.state.displayArray);
  //console.log('name', this.state.displayArray.name);
  //console.log('photo', this.state.displayArray.photo);
    return (
      <View style={{flex: 1}}>
        {this.state.displayArray !== null && this.state.displayArray.length > 0 ? (
          <View style={{ flex: 1}}>
            <SafeAreaView>               
              <FlatList
                data={this.state.displayArray}
                extraData={this.selectedId}
                style={{width: '98%'}}
                onEndReached={() => this.displayBtnLoadMore()}
                renderItem={({item, index, separators })=>
                  <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
                    <ListItem
                      style={{width:'100%'}}
                      containerStyle= {{backgroundColor: index % 2 === 0 ? '#fde3a7' : '#FFF'}}
                      bottomDivider
                      onPress={() => this.props.navigation.navigate('ProductDetails', {productId:parseInt(item.id)})}>
                      <ListItem.Content style={{flexDirection: 'row', justifyContent: 'space-between'}}>
                        {item.photo !== null && item.photo > 0 ? (
                          <Image 
                            source={{uri: URL + item.photo._1_.url}}
                            style={{ width: 25, height: 25}}/> 
                        ) : (
                          <Image 
                            source={require('../../../assets/images/logo.png')}
                            style={{ width: 25, height: 25}}
                          />
                        )};
                        <ListItem.Title style={{width: '65%', fontSize: 16}}>{ ( item.name.length > 20 ) ? item.name.substring(0, 20) + ' ...'  :  item.name}</ListItem.Title>
                        <ListItem.Subtitle style={{ color: '#F78400', position: "absolute", bottom: 0, right: 0 }}>{item.cost}{i18n.t("products.money")}</ListItem.Subtitle>
                      </ListItem.Content>
                    </ListItem>
                  </View>
                }
                keyExtractor={(item,index)=>index.toString()}
                style={{width:"100%"}}
              />
              {this.state.loadMoreVisible === true && this.state.loadMoreVisibleAtEnd === true ? (
                  <Button title=" + " onPress={()=>{this.loadMore()}}></Button>
                ) : null
              }
              <View style={styles.container}>
                <Text>{"\n"}</Text>
                <TouchableOpacity
                  style={styles.touchable2}
                  onPress={() => this.props.navigation.goBack()}
                >
                  <View style={styles.container}>
                    <Button
                      color="#F78400"
                      title= 'Back'
                      onPress={() => this.props.navigation.goBack()}>BACK
                    </Button>
                  </View>
                </TouchableOpacity>
              </View>
              <Text>{"\n\n"}</Text>
            </SafeAreaView>
          </View>
        ) : (
          <View style={styles.container}>
            <Text>{"\n\n" + (this.state.displayArray === null ? i18n.t("products.searching") : i18n.t("products.nodata")) + "\n\n\n"}</Text>
            <Button
              color="#F78400"
              title= 'Back'
              onPress={() => this.props.navigation.goBack()}>BACK
            </Button>
          </View>
        )}
      </View>
    );
  };
}

I'm a little lost in how to do it, so if you have any clue to help me, any lead it would be great. Thanks a lot


Solution

  • This test:

    item.photo !== null && item.photo > 0

    Will not return what you expect. The reason is that when there is no photo, the property is set to an empty string. So the first part of that test should be:

    item.photo !== ''

    Next, when there is a photo, the photo property is an object. So the second part should be:

    item.photo.constructor === 'Object'

    But, that will be compounded if there are more than one photos. Your code suggests you only want the first photo (regardless of how many there may be).

    So if you make the changes I've suggested, it should work as you expect.

    If I were you, I would skip the first test altogether as it isn't necessary now that the second test covers both cases. I recommend just doing this:

    {item.photo.constructor === 'Object' ? (