Как получить доступ к объекту состояния при ошибке функции рендеринга - PullRequest
0 голосов
/ 13 февраля 2019

Я создаю реактивное приложение, и у меня возникла проблема с доступом к состоянию в Render.

Я могу console.log состояния (this.state), и он покажет журнал, что ожидается.

Если я console.log что-то вроде ... (this.state.value) этобудет ошибка, даже если значение присутствует.

Я не могу понять это, и я пробовал весь день!

import React, { Component } from 'react';
import { AsyncStorage, ScrollView, Text, View } from 'react-native';
import { connect } from 'react-redux';
import Loader from '../common/loaders/Loader';
import Header from '../common/header/Header';
import moment from 'moment';
import number from '../../utils/numbers';
import dateLabel from '../../utils/dateLabel';

// Content
import i18n from '../../i18n/i18n';

// Actions
import { loginUser, logoutUser } from '../../actions/authActions';
import { loadingBegin, loadingFinish } from '../../actions/loadingActions';
import { accountsList } from '../../actions/accountsActions';

// Services
import { getAccounts } from '../../services/account';
import { getTransactions } from '../../services/transaction';

// Styles
import common from '../../styles/common';
import styles from './styles';

// --- --- ---
class Home extends Component {

state = {};

constructor(props) {
    super(props);

    if (!this.props.auth.authenticated) this.props.navigation.navigate('Unauthorised');

    this.props.loadingBegin();

    this.state = {
    accounts: [],
    balances: null,
    categories: null,
    transactions: null,
    meta: null,
    };

    this._bootstrapAsync();

    this.props.loadingFinish();
}

componentDidMount = () => {
    const {navigation} = this.props;
    navigation.addListener ('willFocus', () =>{
    console.log('RE-RUNNING PAGE');
    });
}

_bootstrapAsync = async () => {
    // Grab the filter values
    // TODO -> Put filters into Redux store
    this.filters = JSON.parse(await AsyncStorage.getItem('filters'));

    // Check to see if we have any accounts already added
    // Get the accounts info and prime the redux store and state
    const accounts = await getAccounts(this.props.auth);
    this.props.accountsList(accounts);
    this.setState({
    accounts,
    });

    // If there aren't any accounts, redirect to add an account
    if (this.state.accounts && this.state.accounts.length === 0) this.props.navigation.navigate('AccountsNone');

    // Grab the latest transactions and set the state (to be used later)
    let transactionsOptions = {};
    if (this.filters && this.filters.filtersForm) {
    // date set period
    if (this.filters.filtersForm.dates) transactionsOptions.date_type = this.filters.filtersForm.dates;
    // dates between
    if (this.filters.filtersForm.fromDate && this.filters.filtersForm.toDate) {
        transactionsOptions.date_from = this.filters.filtersForm.fromDate;
        transactionsOptions.date_to = this.filters.filtersForm.toDate;
    }
    }
    if (this.filters && this.filters.accountSwitches && this.filters.accountSwitches.length > 0) {
    let obj = this.filters.accountSwitches;
    Object.keys(obj).forEach(key => {
        if (data.accountSwitches[key]) {
        if (!transactionsOptions.account_ids) transactionsOptions.account_ids = {};
        transactionsOptions.account_ids += ',' + key;
        }
    });
    };

    console.log(transactionsOptions);

    let transactions = await getTransactions(this.props.auth, transactionsOptions);
    let meta = transactions.meta;
    let data = transactions.data;

    const balances = this.state.transactions.Balances.map((value) => {                
        return {
            label: moment(value.date, "YYYY-MM-DD").format("MMM Do"), 
            value: value.amount
        }
    });

    const categories = this.state.transactions.Categories;

    this.setState({ 
    transactions: data,
    meta,
    balances,
    categories,
    });
};

render() {
    const { ...props } = this.props;
    const loading = this.props.loading.inProgress;
    let body;

    if (loading) {
    body = <Loader visible={loading} />;
    } else {
    body = (<View>
        <Text style={[styles.balancesDate]}>nuffink</Text>  
    </View>);
    }

    console.log('state.TRANSACTIONS');
    console.log(this.state); // <----------------this works
    console.log(this.state.transactions); // <----------------this doesn't work
    console.log('state.TRANSACTIONS //');

    return (
    <ScrollView
        style={[common.body, styles.container]}
        ref='_main'
        contentContainerStyle={{
        flexGrow: 1
        }}
        stickyHeaderIndices={[0]}
    >

        <Header {...props} txt={"DASHBOARD"} />

        <View style={[common.containerPadding, styles.balances]}>
        <Text>{this.state.trasnactions.value}</Text> <--------------- kills the app and my soul
        </View>
    </ScrollView>
    )
}

}

const mapStateToProps = (state) => {
const { accounts, auth, loading } = state;
return { 
    accounts,
    auth,
    loading
};
};

export default connect(mapStateToProps, { accountsList, loadingBegin, loadingFinish, loginUser, logoutUser })(Home);

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Это потому, что this.state.transactions пуст для начала (установлен в конструкторе), и вы не можете получить доступ к свойству чего-то, что не определено.Кроме того, вы ошиблись "транзакциями" в своей функции рендеринга внутри <Text/>.

. Один из способов решить эту проблему - проверить, определено ли this.state.transactions перед попыткой доступа к this.state.transactions.value, например

{this.state.transactions && <Text>{this.state.transactions.value}</Text>}

0 голосов
/ 13 февраля 2019
<Text>{this.state.trasnactions.value}</Text> <--------------- kills the app and my soul

Цените юмор lol.То, что происходит, это ваш компонент, как и все компоненты будут отображаться один раз без каких-либо данных, если они уже не доступны в вашем состоянии или реквизитах.Это означает, что вся логика, которую вы выполняете в своих обработчиках событий и componentDidMount, не вступит в силу, пока компонент не отобразится хотя бы один раз.то есть: у вас нет данных для работы в вашем сценарии.

Именно поэтому, когда вы пытаетесь получить доступ к this.state.transactions.value на начальном рендере, это убивает ваше приложение, потому что нет данных наначать, и вы пытаетесь отобразить ложное значение.

Чтобы обойти это, вы можете добавить дополнительную логику, подобную этой, которая проверяет, верны ли транзакции.

{this.state.transactions ? 
   <Text>{this.state.transactions.value}</Text>
: null }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...