首页 > 解决方案 > 如何在渲染函数错误中访问状态对象

问题描述

我正在创建一个 react-native 应用程序,并且在访问渲染中的状态时遇到问题。

我可以控制台记录状态(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);

标签: reactjsreact-nativereduxreact-redux

解决方案


<Text>{this.state.trasnactions.value}</Text> <--------------- kills the app and my soul

欣赏幽默哈哈。正在发生的是你的组件,就像所有组件都将在没有任何数据的情况下呈现一次,除非你的 state 或 props 中已经可用。这意味着在组件至少渲染一次之前,您在事件处理程序和 componentDidMount 中执行的所有逻辑都不会生效。即:您在您的场景中没有可使用的数据。

这就是为什么当您尝试在初始渲染上访问 this.state.transactions.value 时,它​​会杀死您的应用程序,因为在开始时没有数据并且您正在尝试渲染虚假值。

要解决此问题,您可以添加一些额外的逻辑,例如检查交易是否真实。

{this.state.transactions ? 
   <Text>{this.state.transactions.value}</Text>
: null }

推荐阅读