Почему, когда я переключаюсь между двумя вкладками со списками, я получаю ошибку «undefined не является объектом»? - PullRequest
0 голосов
/ 25 октября 2018

Заранее благодарю за помощь - я очень новичок в разработке приложений.

В моем приложении React Native есть навигатор по вкладкам с тремя вкладками, одна для канала, одна для списка событий иодин для списка пользователей.Когда я переключаюсь со своей вкладки фида - которая отображает список сообщений - обратно на вкладку моих пользователей и нажимаю на элемент списка, чтобы просмотреть профиль пользователя, я получаю следующую ошибку: Ошибка при нажатии на элемент списка

Я подозреваю, что эта проблема как-то связана с тем, как я создал списки.

Для моей вкладки фида, вот как я определяю свой список сообщений:

  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', чтобы сгенерировать ключ для каждого элемента списка.Однако произошла та же ошибка.Если это важно: компонент «Список», который я здесь использую, взят из библиотеки Native-Base.

ОБНОВЛЕНИЕ 2:

В ответ на комментарий приведена дополнительная информация о том, как я обрабатываю состояние с использованием приставки.

Для моего фидавкладка (список сообщений), файл действий:

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 });
    });
  };
};

и соответствующий файл редуктора:

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() });
      });
  };
};

И соответствующий файл редуктора:

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;
  }
};

Я управляю навигацией с помощью библиотеки «response-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',
    }
  }
);

Надеюсь, это достаточно информации, но, пожалуйста, прокомментируйте, если вам нужно увидеть другие части моего кода.

Спасибо

1 Ответ

0 голосов
/ 21 января 2019

Я нашел ответ!Я не совсем уверен, почему, но кажется, что список нужен ключ.поэтому я добавил свойство случайного ключа в компонент List с помощью функции math.random (), и оно исправило ошибку.

...