reactjs - 如何在渲染函数错误中访问状态对象
问题描述
我正在创建一个 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);
解决方案
<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 }
推荐阅读
- jquery - 导航栏隐藏和显示在小屏幕上的切换会弄乱大屏幕
- python - 预测不相关数据的张量流神经网络模型
- javascript - 如何在 sagas 中测试多个 takeEvery?
- android - 在列表视图中交替颜色,但需要有一个起始颜色
- python - 使用python在文本中搜索字符串
- mysql - 根据表 2 中的单列返回表 1 的值
- json - ConvertFrom-Json : 传入的对象无效,应为 ':' 或 '}'
- android - 使用 FrameLayout 时 TextInputLayout 文本标题消失了
- python - 合并请求中的冗余参数
- node.js - Express 消息 '!=' 在 Pug 中引发错误