У меня очень странная проблема, когда я даже не знаю, с чего начать отладку, поскольку это происходит только тогда, когда я запускаю приложение в тестовый полет. В основном я пытаюсь загрузить каналы на основе геолокации. Некоторые загружаются автоматически, а затем загружаются, если они находятся менее чем в 100 милях от горы (давайте назовем эти ОБЩЕСТВЕННЫЕ и ЧАСТНЫЕ каналы - оба из них находятся в одном списке). У меня есть эти 2 вызова Firebase в моем создателе действий и помещаю их в массив, а затем вызываю dispatch после. У меня есть проблема с FlatList, где он загружает каналы PUBLIC и только когда я прокручиваю, делаю PRIVATE каналы. Я пробовал несколько вещей, в том числе наиболее распространенную из этой конкретной проблемы с github (обновление плоского списка) 'removeClippedSubviews = {false}', дополнительные данные, чистые компоненты и т. Д., Но ни одна из них не сработала.
Вместо этого я нашел способ обойти это (я знаю, что это не самое лучшее, но я просто хочу решение, которое пока работает), просто установив тайм-аут и дождавшись каналов перед отправкой действия:
setTimeout(function(){ dispatch(loadPublicChannelsSuccess(data)); }, 10);
К сожалению, сейчас наступает момент, когда возникает сумасшедшая проблема. По сути, это работает для отладки, выпуска / всего, что я пробовал с XCode, но когда оно попадает на мое устройство, метод рендеринга в основном находится наиндикатор загрузки, пока я не переключаю вкладки с реагирующей навигацией. Это не имеет смысла для меня, так как это происходит не всегда (возможно, 80%) времени, и пока только в испытательном полете. Я никогда не видел этого до того, как установил тайм-аут, поэтому не совсем уверен, с чего начать:
render() {
const {loadPublicChannels, loading, publicChannels, checkedInMountain, selectedMountain} = this.props;
return !loadPublicChannels && publicChannels && !loading
? (
<MessagePanelPublic publicChannels={publicChannels} selectedMountain={selectedMountain}/>
) : (
<LoadingAnimation />
);
}
действия
export const getUserPublicChannels = () => {
return (dispatch, state) => {
dispatch(loadPublicChannels());
// get all mountains within distance specified
let mountainsInRange = state().session.mountainsInRange;
// get the user selected mountain
let selectedMountain = state().session.selectedMountain;
// see if the selected mountain is in range to add on additional channels
let currentMountain;
mountainsInRange
? (currentMountain =
mountainsInRange.filter(mountain => mountain.id === selectedMountain)
.length === 1
? true
: false)
: (currentMountain = false);
// mountain public channels (don't need to be within distance)
let currentMountainPublicChannelsRef = FIREBASE_REF_CHANNEL_INFO.child(
"Public"
)
.child(`${selectedMountain}`)
.child("Public");
// mountain private channels- only can see if within range (geolocation)
let currentMountainPrivateChannelsRef = FIREBASE_REF_CHANNEL_INFO.child(
"Public"
)
.child(`${selectedMountain}`)
.child("Private");
// get public channels
return currentMountainPublicChannelsRef
.orderByChild("key")
.once("value")
.then(snapshot => {
let publicChannelsToDownload = [];
snapshot.forEach(channelSnapshot => {
let channelId = channelSnapshot.key;
let channelInfo = channelSnapshot.val();
// add the channel ID to the download list
publicChannelsToDownload.push({ id: channelId, info: channelInfo });
});
// if mountain exists then get private channels/ if in range
if (currentMountain) {
currentMountainPrivateChannelsRef
.orderByChild("key")
.once("value")
.then(snapshot => {
snapshot.forEach(channelSnapshot => {
let channelId = channelSnapshot.key;
let channelInfo = channelSnapshot.val();
publicChannelsToDownload.push({
id: channelId,
info: channelInfo
});
});
});
}
return publicChannelsToDownload;
})
.then(data => {
setTimeout(function(){ dispatch(loadPublicChannelsSuccess(data)); }, 10);
});
};
};
редуктор, связанный с общедоступными каналами
case types.LOAD_PUBLIC_CHANNELS:
return {
...state,
loadPublicChannels: true
};
case types.LOAD_PUBLIC_CHANNELS_SUCCESS:
console.log("PUBLIC");
console.log(action.publicChannels);
console.log(action);
return {
...state,
publicChannels: action.publicChannels,
loadPublicChannels: false,
messages: {}
};
case types.LOAD_PUBLIC_CHANNELS_ERROR:
return {
...state,
channelsPublicError: action.error,
loadPublicChannels: false
};
контейнер, который вызывает mapStateToProps и mapDispatchToProps
class MessagePanelPublicContainer extends Component {
constructor(props) {
super(props);
}
// get public and private channels from redux
async componentDidMount() {
this.props.getUserPrivateChannels();
this.props.loadCurrentUser();
// this.props.getUserPublicChannels();
}
componentDidUpdate(prevProps) {
if (this.props.mountainsInRange && prevProps.mountainsInRange !== this.props.mountainsInRange || prevProps.selectedMountain !== this.props.selectedMountain) {
this.props.getUserPublicChannels();
}
}
lessThan12HourAgo = (date) => {
return moment(date).isAfter(moment().subtract(12, 'hours'));
}
render() {
const {loadPublicChannels, loading, publicChannels, checkedInMountain, selectedMountain} = this.props;
return !loadPublicChannels && publicChannels && !loading
? (
<MessagePanelPublic publicChannels={publicChannels} selectedMountain={selectedMountain}/>
) : (
<LoadingAnimation />
);
}
}
const mapStateToProps = state => {
return {
publicChannels: state.chat.publicChannels,
loadPublicChannels: state.chat.loadPublicChannels,
currentUser: state.chat.currentUser,
loading: state.chat.loadCurrentUser,
mountainsInRange: state.session.mountainsInRange,
selectedMountain: state.session.selectedMountain,
};
}
const mapDispatchToProps = {
loadCurrentUser,
getUserPublicChannels,
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(MessagePanelPublicContainer);
компонент
import React, { Component } from "react";
import { View, Text, FlatList, ImageComponent } from "react-native";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { ListItem, Icon, Button } from "react-native-elements";
import { withNavigation } from "react-navigation";
import LinearGradient from "react-native-linear-gradient";
import styles from "./Styles";
import moment from 'moment';
import FastImage from 'react-native-fast-image';
class MessagePanelPublicComponent extends Component {
render() {
// rendering all public channels
const renderPublicChannels = ({ item }) => {
return (
<ListItem
leftAvatar={{
source: { uri: item.info.ChannelPicture },
rounded: false,
overlayContainerStyle: { backgroundColor: "white" },
ImageComponent: FastImage
}}
title={item.info.Name}
titleStyle={styles.title}
chevron={true}
bottomDivider={true}
id={item.Name}
containerStyle={styles.listItemStyle}
/>
);
};
const renderText = () => {
return (
<View style={styles.extraTextContainer}>
<Text style={styles.extraText}>
Get within 100 miles from resort or select a closer resort to see more channels...
</Text>
<Icon
name="map-marker"
type="font-awesome"
size={40}
iconStyle={styles.extraIcon}
/>
</View>
);
};
return (
<View style={styles.container}>
<View style={styles.channelList}>
<FlatList
data={this.props.publicChannels}
renderItem={renderPublicChannels}
// keyExtractor={item => item.Name}
keyExtractor={(item, index) => index.toString()}
extraData={this.props.publicChannels}
removeClippedSubviews={false}
/>
{this.props.publicChannels.length < 3 ? renderText() : null}
</View>
</View>
);
}
}