为什么当我在带有列表的两个选项卡之间切换时,出现错误 'undefined is not an object'?
Why is it that when I switch between two tabs with lists, I get the error 'undefined is not an object'?
提前感谢您的帮助 - 我是应用程序开发的新手。
我的 React Native 应用程序有一个选项卡导航器,其中包含三个选项卡,一个用于提要,一个用于事件列表,一个用于用户列表。当我从呈现帖子列表的提要选项卡切换回我的用户选项卡并单击列表项以查看用户的个人资料时,我收到以下错误:Error when clicking on list item
我怀疑这个问题与我创建列表的方式有关。
对于我的 Feed 选项卡,这是我定义帖子列表的方式:
renderFeed = () => {
if (this.props.loadingList) {
return <Spinner />;
} else if (this.props.error) {
return (<Text>{this.props.error}</Text>);
} return (
<List
enableEmptySections
dataArray={this.props.feedData}
renderRow={this.renderPost}
/>
);
}
renderPost = (post) => {
const { name, postContent, time } = post;
return (
<Card style={{ flex: 0 }}>
<CardItem>
<Left>
<Thumbnail source={{ uri: 'https://cdn.images.express.co.uk/img/dynamic/4/590x/LeBron-James-has-until-June-29-to-opt-out-of-his-contract-with-the-Cavaliers-978390.jpg?r=1529715616214' }} />
<Body>
<Text>{name}</Text>
<Text note>{time}</Text>
</Body>
</Left>
</CardItem>
<CardItem>
<Body>
<Text>{postContent}</Text>
</Body>
</CardItem>
</Card>
);
}
对于我的用户选项卡,这是我定义用户列表的方式:
renderActivesList = () => {
if (this.props.loadingList) {
return <Spinner />;
} else if (this.props.error) {
return (<Text>{this.props.error}</Text>);
} return (
<List
enableEmptySections
dataArray={this.props.listData}
renderRow={this.renderRow}
/>
);
}
renderRow = (active) => {
const name = `${active.firstName} ${active.lastName}`;
return (
<ListItem
key={name}
button
onPress={() => { this.onActiveSelect(name, active.rank); }}
>
<Body>
<Text>{name}</Text>
<Text note>{active.position}</Text>
</Body>
<Right>
<Text note>{active.rank}</Text>
</Right>
</ListItem>
);
}
我觉得这里肯定存在一些冲突,因为错误仅在单击用户列表中的用户时发生,并且仅在我切换到提要选项卡(并因此呈现它)之后才会发生。
请告诉我您的想法。谢谢!
更新 1:
我尝试使用列表属性 'keyExtractor' 为每个列表项生成一个键。但是发生了同样的错误。如果它很重要:我在这里使用的 'List' 组件来自 Native-Base 库。
更新 2:
作为对评论的回应,这里有一些关于我如何使用 redux 处理状态的附加信息。
对于我的提要选项卡(帖子列表),操作文件是:
import firebase from 'firebase';
import _ from 'lodash';
import {
POST_CHANGED,
SEND_BUTTON_PRESSED,
POST_SUCCESS,
REQUEST_FEED_DATA,
REQUEST_FEED_DATA_SUCCESS
} from '../constants/Types';
export const postChanged = (text) => {
return {
type: POST_CHANGED,
payload: text
};
};
export const sendButtonPressed = (postContent, firstName, lastName, rank, organization) => {
if (postContent) {
return (dispatch) => {
dispatch({ type: SEND_BUTTON_PRESSED });
const name = `${firstName} ${lastName}`;
const time = new Date().toLocaleString();
const comments = 0;
firebase.database().ref(`${organization}/posts`)
.push({ name, rank, time, comments, postContent })
.then(dispatch({ type: POST_SUCCESS }));
};
} return { type: '' };
};
export const fetchFeed = (organization) => {
return (dispatch) => {
dispatch({ type: REQUEST_FEED_DATA });
firebase.database().ref(`${organization}/posts`)
.on('value', snapshot => {
const array = _.map(snapshot.val(), (val) => {
return { ...val };
});
const feed = array.reverse();
dispatch({ type: REQUEST_FEED_DATA_SUCCESS, payload: feed });
});
};
};
对应的reducer文件为:
import {
POST_CHANGED,
SEND_BUTTON_PRESSED,
POST_SUCCESS,
REQUEST_FEED_DATA,
REQUEST_FEED_DATA_SUCCESS
} from '../constants/Types';
const INITIAL_STATE = {
postContent: '',
posting: false,
loadingList: true,
feedData: []
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case POST_CHANGED:
return { ...state, postContent: action.payload };
case SEND_BUTTON_PRESSED:
return { ...state, posting: true };
case POST_SUCCESS:
return { ...state, posting: false, postContent: '' };
case REQUEST_FEED_DATA:
return { ...state, loadingList: true };
case REQUEST_FEED_DATA_SUCCESS:
return { ...state, feedData: action.payload, loadingList: false };
default:
return { state };
}
};
对于我的用户选项卡(用户列表),操作文件是:
import firebase from 'firebase';
import _ from 'lodash';
import {
REQUEST_LIST_DATA,
REQUEST_LIST_DATA_SUCCESS,
REQUEST_LIST_DATA_FAILED,
FETCH_SELECTED_PROFILE,
FETCH_SELECTED_PROFILE_SUCCESS
} from '../constants/Types';
export const fetchActivesList = (organization) => {
return (dispatch) => {
dispatch({ type: REQUEST_LIST_DATA });
firebase.database().ref(`${organization}/activesList`)
.on('value', snapshot => {
const activesList = _.map(snapshot.val(), (val, rank) => {
return { ...val, rank };
});
dispatch({ type: REQUEST_LIST_DATA_SUCCESS, payload: activesList });
});
};
};
export const fetchSelectedProfile = (organization, rank) => {
return (dispatch) => {
dispatch({ type: FETCH_SELECTED_PROFILE });
firebase.database().ref(`${organization}/profiles/${rank}`)
.on('value', snapshot => {
dispatch({ type: FETCH_SELECTED_PROFILE_SUCCESS, payload: snapshot.val() });
});
};
};
对应的reducer文件为:
import {
REQUEST_LIST_DATA,
REQUEST_LIST_DATA_SUCCESS,
REQUEST_LIST_DATA_FAILED,
FETCH_SELECTED_PROFILE,
FETCH_SELECTED_PROFILE_SUCCESS
} from '../constants/Types';
const INITIAL_STATE = {
loadingList: false,
loadingProfile: false,
error: '',
listData: [],
//selectedProfileStats
selectedAdmin: false,
selectedBrotherhoods: 0,
selectedChapters: 0,
selectedCommunityService: 0,
selectedDues: 0,
selectedFirstName: '',
selectedLastName: '',
selectedMixers: 0,
selectedPosition: '',
selectedOrganization: '',
selectedRank: '',
selectedGoodStanding: true,
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case REQUEST_LIST_DATA:
return { ...state, loadingList: true };
case REQUEST_LIST_DATA_SUCCESS:
return { ...state, listData: action.payload, loadingList: false, error: '' };
case REQUEST_LIST_DATA_FAILED:
return { ...state, error: action.payload, loadingList: false };
case FETCH_SELECTED_PROFILE:
return { ...state, loadingProfile: true };
case FETCH_SELECTED_PROFILE_SUCCESS:
return {
...state,
loadingProfile: false,
selectedAdmin: action.payload.admin,
selectedBrotherhoods: action.payload.brotherhoods,
selectedChapters: action.payload.chapters,
selectedCommunityService: action.payload.communityService,
selectedDues: action.payload.dues,
selectedFirstName: action.payload.firstName,
selectedLastName: action.payload.lastName,
selectedMixers: action.payload.mixers,
selectedPosition: action.payload.position,
selectedGoodStanding: action.payload.goodStanding,
selectedRank: action.payload.rank
};
default:
return state;
}
};
我正在使用 'react-navigation' 库处理导航。此代码分布在两个文件中,一个是名为 'AppNavigator.js' 的切换导航器,如下所示:
import { createSwitchNavigator, createStackNavigator } from 'react-navigation';
import MainTabNavigator from './MainTabNavigator';
import LoginScreen from '../screens/auth/LoginScreen';
import RegisterChapterScreen from '../screens/auth/RegisterChapterScreen';
import JoinChapterScreen from '../screens/auth/JoinChapterScreen';
const AuthStack = createStackNavigator(
{
Login: LoginScreen,
RegChapter: RegisterChapterScreen,
joinChapter: JoinChapterScreen
},
{
initialRouteName: 'Login'
}
);
export default createSwitchNavigator(
{
// You could add another route here for authentication.
// Read more at https://reactnavigation.org/docs/en/auth-flow.html
Auth: AuthStack,
Main: MainTabNavigator
},
{
initialRouteName: 'Auth'
}
);
第二个文件是一个名为 'MainTabNavigator' 的选项卡导航器,如下所示:
import React from 'react';
import { Platform } from 'react-native';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
import TabBarIcon from '../components/TabBarIcon';
import FeedScreen from '../screens/feedTab/FeedScreen';
import EventsScreen from '../screens/eventsTab/EventsScreen';
import CreateEventScreen from '../screens/eventsTab/CreateEventScreen';
import ActivesScreen from '../screens/activesTab/ActivesScreen';
import ProfileScreen from '../screens/activesTab/ProfileScreen';
//Feed Tab Navigation Setup
const FeedStack = createStackNavigator({
Feed: FeedScreen,
});
FeedStack.navigationOptions = {
tabBarLabel: 'Feed',
tabBarIcon: ({ focused, tintColor }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? `ios-paper${focused ? '' : '-outline'}` : 'md-paper'}
color={tintColor}
/>
),
};
//Events Tab Navigation Setup
const EventsStack = createStackNavigator({
EventsList: EventsScreen,
CreateEvent: CreateEventScreen
});
EventsStack.navigationOptions = {
tabBarLabel: 'Events',
tabBarIcon: ({ focused, tintColor }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? `ios-person${focused ? '' : '-outline'}` : 'md-person'}
color={tintColor}
/>
),
};
//Actives Tab Navigation Setup
const ActivesStack = createStackNavigator({
Actives: ActivesScreen,
SelectedProfile: ProfileScreen,
});
ActivesStack.navigationOptions = {
tabBarLabel: 'Actives',
tabBarIcon: ({ focused, tintColor }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? `ios-contacts${focused ? '' : '-outline'}` : 'md-contacts'}
color={tintColor}
/>
),
};
export default createBottomTabNavigator(
{
ActivesStack,
FeedStack,
EventsStack,
},
{
tabBarOptions: {
activeTintColor: 'red',
inactiveTintColor: 'gray',
}
}
);
希望这些信息足够了,但如果您需要查看我代码的其他部分,请发表评论。
谢谢
我找到答案了!我不完全确定为什么,但似乎 List 需要一把钥匙。所以我使用 math.random() 函数向列表组件添加了一个随机键 属性 并修复了错误。
提前感谢您的帮助 - 我是应用程序开发的新手。
我的 React Native 应用程序有一个选项卡导航器,其中包含三个选项卡,一个用于提要,一个用于事件列表,一个用于用户列表。当我从呈现帖子列表的提要选项卡切换回我的用户选项卡并单击列表项以查看用户的个人资料时,我收到以下错误:Error when clicking on list item
我怀疑这个问题与我创建列表的方式有关。
对于我的 Feed 选项卡,这是我定义帖子列表的方式:
renderFeed = () => {
if (this.props.loadingList) {
return <Spinner />;
} else if (this.props.error) {
return (<Text>{this.props.error}</Text>);
} return (
<List
enableEmptySections
dataArray={this.props.feedData}
renderRow={this.renderPost}
/>
);
}
renderPost = (post) => {
const { name, postContent, time } = post;
return (
<Card style={{ flex: 0 }}>
<CardItem>
<Left>
<Thumbnail source={{ uri: 'https://cdn.images.express.co.uk/img/dynamic/4/590x/LeBron-James-has-until-June-29-to-opt-out-of-his-contract-with-the-Cavaliers-978390.jpg?r=1529715616214' }} />
<Body>
<Text>{name}</Text>
<Text note>{time}</Text>
</Body>
</Left>
</CardItem>
<CardItem>
<Body>
<Text>{postContent}</Text>
</Body>
</CardItem>
</Card>
);
}
对于我的用户选项卡,这是我定义用户列表的方式:
renderActivesList = () => {
if (this.props.loadingList) {
return <Spinner />;
} else if (this.props.error) {
return (<Text>{this.props.error}</Text>);
} return (
<List
enableEmptySections
dataArray={this.props.listData}
renderRow={this.renderRow}
/>
);
}
renderRow = (active) => {
const name = `${active.firstName} ${active.lastName}`;
return (
<ListItem
key={name}
button
onPress={() => { this.onActiveSelect(name, active.rank); }}
>
<Body>
<Text>{name}</Text>
<Text note>{active.position}</Text>
</Body>
<Right>
<Text note>{active.rank}</Text>
</Right>
</ListItem>
);
}
我觉得这里肯定存在一些冲突,因为错误仅在单击用户列表中的用户时发生,并且仅在我切换到提要选项卡(并因此呈现它)之后才会发生。
请告诉我您的想法。谢谢!
更新 1:
我尝试使用列表属性 'keyExtractor' 为每个列表项生成一个键。但是发生了同样的错误。如果它很重要:我在这里使用的 'List' 组件来自 Native-Base 库。
更新 2:
作为对评论的回应,这里有一些关于我如何使用 redux 处理状态的附加信息。
对于我的提要选项卡(帖子列表),操作文件是:
import firebase from 'firebase';
import _ from 'lodash';
import {
POST_CHANGED,
SEND_BUTTON_PRESSED,
POST_SUCCESS,
REQUEST_FEED_DATA,
REQUEST_FEED_DATA_SUCCESS
} from '../constants/Types';
export const postChanged = (text) => {
return {
type: POST_CHANGED,
payload: text
};
};
export const sendButtonPressed = (postContent, firstName, lastName, rank, organization) => {
if (postContent) {
return (dispatch) => {
dispatch({ type: SEND_BUTTON_PRESSED });
const name = `${firstName} ${lastName}`;
const time = new Date().toLocaleString();
const comments = 0;
firebase.database().ref(`${organization}/posts`)
.push({ name, rank, time, comments, postContent })
.then(dispatch({ type: POST_SUCCESS }));
};
} return { type: '' };
};
export const fetchFeed = (organization) => {
return (dispatch) => {
dispatch({ type: REQUEST_FEED_DATA });
firebase.database().ref(`${organization}/posts`)
.on('value', snapshot => {
const array = _.map(snapshot.val(), (val) => {
return { ...val };
});
const feed = array.reverse();
dispatch({ type: REQUEST_FEED_DATA_SUCCESS, payload: feed });
});
};
};
对应的reducer文件为:
import {
POST_CHANGED,
SEND_BUTTON_PRESSED,
POST_SUCCESS,
REQUEST_FEED_DATA,
REQUEST_FEED_DATA_SUCCESS
} from '../constants/Types';
const INITIAL_STATE = {
postContent: '',
posting: false,
loadingList: true,
feedData: []
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case POST_CHANGED:
return { ...state, postContent: action.payload };
case SEND_BUTTON_PRESSED:
return { ...state, posting: true };
case POST_SUCCESS:
return { ...state, posting: false, postContent: '' };
case REQUEST_FEED_DATA:
return { ...state, loadingList: true };
case REQUEST_FEED_DATA_SUCCESS:
return { ...state, feedData: action.payload, loadingList: false };
default:
return { state };
}
};
对于我的用户选项卡(用户列表),操作文件是:
import firebase from 'firebase';
import _ from 'lodash';
import {
REQUEST_LIST_DATA,
REQUEST_LIST_DATA_SUCCESS,
REQUEST_LIST_DATA_FAILED,
FETCH_SELECTED_PROFILE,
FETCH_SELECTED_PROFILE_SUCCESS
} from '../constants/Types';
export const fetchActivesList = (organization) => {
return (dispatch) => {
dispatch({ type: REQUEST_LIST_DATA });
firebase.database().ref(`${organization}/activesList`)
.on('value', snapshot => {
const activesList = _.map(snapshot.val(), (val, rank) => {
return { ...val, rank };
});
dispatch({ type: REQUEST_LIST_DATA_SUCCESS, payload: activesList });
});
};
};
export const fetchSelectedProfile = (organization, rank) => {
return (dispatch) => {
dispatch({ type: FETCH_SELECTED_PROFILE });
firebase.database().ref(`${organization}/profiles/${rank}`)
.on('value', snapshot => {
dispatch({ type: FETCH_SELECTED_PROFILE_SUCCESS, payload: snapshot.val() });
});
};
};
对应的reducer文件为:
import {
REQUEST_LIST_DATA,
REQUEST_LIST_DATA_SUCCESS,
REQUEST_LIST_DATA_FAILED,
FETCH_SELECTED_PROFILE,
FETCH_SELECTED_PROFILE_SUCCESS
} from '../constants/Types';
const INITIAL_STATE = {
loadingList: false,
loadingProfile: false,
error: '',
listData: [],
//selectedProfileStats
selectedAdmin: false,
selectedBrotherhoods: 0,
selectedChapters: 0,
selectedCommunityService: 0,
selectedDues: 0,
selectedFirstName: '',
selectedLastName: '',
selectedMixers: 0,
selectedPosition: '',
selectedOrganization: '',
selectedRank: '',
selectedGoodStanding: true,
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case REQUEST_LIST_DATA:
return { ...state, loadingList: true };
case REQUEST_LIST_DATA_SUCCESS:
return { ...state, listData: action.payload, loadingList: false, error: '' };
case REQUEST_LIST_DATA_FAILED:
return { ...state, error: action.payload, loadingList: false };
case FETCH_SELECTED_PROFILE:
return { ...state, loadingProfile: true };
case FETCH_SELECTED_PROFILE_SUCCESS:
return {
...state,
loadingProfile: false,
selectedAdmin: action.payload.admin,
selectedBrotherhoods: action.payload.brotherhoods,
selectedChapters: action.payload.chapters,
selectedCommunityService: action.payload.communityService,
selectedDues: action.payload.dues,
selectedFirstName: action.payload.firstName,
selectedLastName: action.payload.lastName,
selectedMixers: action.payload.mixers,
selectedPosition: action.payload.position,
selectedGoodStanding: action.payload.goodStanding,
selectedRank: action.payload.rank
};
default:
return state;
}
};
我正在使用 'react-navigation' 库处理导航。此代码分布在两个文件中,一个是名为 'AppNavigator.js' 的切换导航器,如下所示:
import { createSwitchNavigator, createStackNavigator } from 'react-navigation';
import MainTabNavigator from './MainTabNavigator';
import LoginScreen from '../screens/auth/LoginScreen';
import RegisterChapterScreen from '../screens/auth/RegisterChapterScreen';
import JoinChapterScreen from '../screens/auth/JoinChapterScreen';
const AuthStack = createStackNavigator(
{
Login: LoginScreen,
RegChapter: RegisterChapterScreen,
joinChapter: JoinChapterScreen
},
{
initialRouteName: 'Login'
}
);
export default createSwitchNavigator(
{
// You could add another route here for authentication.
// Read more at https://reactnavigation.org/docs/en/auth-flow.html
Auth: AuthStack,
Main: MainTabNavigator
},
{
initialRouteName: 'Auth'
}
);
第二个文件是一个名为 'MainTabNavigator' 的选项卡导航器,如下所示:
import React from 'react';
import { Platform } from 'react-native';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
import TabBarIcon from '../components/TabBarIcon';
import FeedScreen from '../screens/feedTab/FeedScreen';
import EventsScreen from '../screens/eventsTab/EventsScreen';
import CreateEventScreen from '../screens/eventsTab/CreateEventScreen';
import ActivesScreen from '../screens/activesTab/ActivesScreen';
import ProfileScreen from '../screens/activesTab/ProfileScreen';
//Feed Tab Navigation Setup
const FeedStack = createStackNavigator({
Feed: FeedScreen,
});
FeedStack.navigationOptions = {
tabBarLabel: 'Feed',
tabBarIcon: ({ focused, tintColor }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? `ios-paper${focused ? '' : '-outline'}` : 'md-paper'}
color={tintColor}
/>
),
};
//Events Tab Navigation Setup
const EventsStack = createStackNavigator({
EventsList: EventsScreen,
CreateEvent: CreateEventScreen
});
EventsStack.navigationOptions = {
tabBarLabel: 'Events',
tabBarIcon: ({ focused, tintColor }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? `ios-person${focused ? '' : '-outline'}` : 'md-person'}
color={tintColor}
/>
),
};
//Actives Tab Navigation Setup
const ActivesStack = createStackNavigator({
Actives: ActivesScreen,
SelectedProfile: ProfileScreen,
});
ActivesStack.navigationOptions = {
tabBarLabel: 'Actives',
tabBarIcon: ({ focused, tintColor }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? `ios-contacts${focused ? '' : '-outline'}` : 'md-contacts'}
color={tintColor}
/>
),
};
export default createBottomTabNavigator(
{
ActivesStack,
FeedStack,
EventsStack,
},
{
tabBarOptions: {
activeTintColor: 'red',
inactiveTintColor: 'gray',
}
}
);
希望这些信息足够了,但如果您需要查看我代码的其他部分,请发表评论。
谢谢
我找到答案了!我不完全确定为什么,但似乎 List 需要一把钥匙。所以我使用 math.random() 函数向列表组件添加了一个随机键 属性 并修复了错误。