Philipe Neves
Philipe Neves

Reputation: 35

How to get data before the component mount?

I've a screen in my app that loads some data. But I think the component is mounting before the them load. Probably because the token was not generated yet. How can I do to this not happen without using a timeout, maybe using a life cycle method from react native? ps: When I save the file 2 or three times the data loads, before the component is empty.

My code:

import React, { Component } from 'react'
import {
    View, 
    FlatList,
    Text
} from 'react-native'

import Intl from 'intl'
import 'intl/locale-data/jsonp/pt-BR'
import { connect } from 'react-redux'

import { loadPortifolio } from '../../../../store/actions/portifolio'
import CardTitle from '../CardComponents/CardTitle'
import MoneyIcon from '../../../../assets/images/money.svg'
import SavingsIcon from '../../../../assets/images/savings.svg'
import BankIcon from '../../../../assets/images/bank.svg'
import CartIcon from '../../../../assets/images/cart.svg'

import styles from './styles'


class Portifolio extends Component {
    state = {
        list: [],
    }

    componentDidMount = async() => {
        await this.props.onLoadPortifolio()
        this.setState({list: Object.entries(this.props.list).sort()}) //This is the part that I want to load before the component mount.
    }  

    renderListDescription = (description) => {
        let newDescription = ''
        if (description == 'money'){
            return newDescription = 'DINHEIRO'
        } else if (description == 'contacorrente') {
            return newDescription = 'CONTA CORRENTE'
        } else if (description == 'credit') {
            return newDescription = 'CARTÃO DE CRÉDITO'
        } else {
            return newDescription = 'POUPANÇA'
        }
    }

    renderListIcon = (description) => {
        if (description == 'money'){
            return <MoneyIcon width={24} height={24} />
        } else if (description == 'contacorrente') {
            return <BankIcon width={24} height={24} />
        } else if (description == 'credit') {
            return <CartIcon width={24} height={24} />
        } else {
            return <SavingsIcon width={24} height={24} />
        } 
    }

    render(){
        return (
            <View style={styles.container}>
                <CardTitle title='SALDOS CARTEIRAS'/>

                <FlatList
                    data={this.state.list.slice(0, 4)}
                    keyExtractor={(item, index) => item.key}
                    renderItem={({item}) =>

                        <View style={styles.list}>
                            <View style={styles.listIconDescription}>
                                {this.renderListIcon(item[0])}
                                <Text style={styles.descriptionText}>{this.renderListDescription(item[0])}</Text>
                            </View>
                            <Text 
                                style={[item[1] >= 0 ?  {color: '#028FFF'} : 
                                    {color: '#9F261A'}, styles.valueText]}>
                                        {Intl.NumberFormat('pt-BR', 
                                            { style: 'currency', currency: 'BRL' })
                                            .format(item[1])}
                            </Text>
                        </View>
                    }
                />
            </View>
        )
    }
}

const mapStateToProps = ({ portifolio }) => {
    return {
        list: portifolio.list,
        loadError: portifolio.loadError,
    }
}

const mapDispatchToProps = dispatch => {
    return {
        onLoadPortifolio: () => dispatch(loadPortifolio())
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(Portifolio)

Upvotes: 2

Views: 13492

Answers (1)

The Lazy Programmer
The Lazy Programmer

Reputation: 125

You can use the lifecycle method

componentWillMount

This is the most logical place to fetch data. Fetch it just before the component will mount, right? Although there is a big but...

There are a couple of problems though.

1) First, the big one: componentWillMount is deprecated as of React 16.3 (March 2018).

2) An API call with fetch or axios inside componentWillMount will not return before the first render. This means the component will render with empty data at least once.

Because of the nature of async events in JavaScript, when you kick off an API call, the browser goes back to doing other work in the meantime. When React is rendering a component, it doesn’t wait for componentWillMount to finish whatever it started – React marches on and continues to render.

There is no way to “pause” rendering to wait for data to arrive. You cannot return a promise from componentWillMount or wrangle in a setTimeout somehow. The right way to handle this is to set up the component’s initial state so that even when it renders with no data, it still looks acceptable.

So what can you do? You could render an empty list or display placeholders, or maybe show a little hint to the new user about how to get started. Whatever you do, don’t try to iterate over an array of undefined or you’ll get the dreaded “Cannot read property ‘map’ of undefined” error.

Upvotes: 4

Related Questions