React Native - 无法使用条件渲染视图
Posted
技术标签:
【中文标题】React Native - 无法使用条件渲染视图【英文标题】:React Native - can't get view to render with conditional 【发布时间】:2019-02-26 21:49:27 【问题描述】:我在尝试渲染元素的地方有这段代码:
render()
//console.log('this.state.showRespondTo:',this.state.showRespondTo);
return (
<View style=flex:1>
this.displayMessage()
<TouchableWithoutFeedback onPress=Keyboard.dismiss>
<View style=styles.container>
<MultiSelectList
style=backgroundColor: '#ffe4c4'
data=this.state.items
renderItem=this.renderListItems
numColumns=2
contentContainerStyle=
onEndReachedThreshold=0.5
maxToRenderPerBatch=2
initialNumToRender=4
ListHeaderComponent=this.renderHeader
getItemLayout=(data, index) => (
length: Dimensions.get('window').height/2, offset: Dimensions.get('window').height/2 * index, index
)
backgroundColor=this.state.backgroundColor
//contentContainerStyle=backgroundColor: '#1e4683'
/>
</View>
</TouchableWithoutFeedback>
</View>
);
displayMessage()
if(this.state.showRespondTo)
console.log('this.state.showRespondTo:', this.state.showRespondTo);
return ( <RespondToInquiry/> )
这就是RespondToInquiry
是:
import React, Component from 'react'
import
Text,
TextInput,
TouchableOpacity,
TouchableHighlight,
TouchableWithoutFeedback,
View,
Dimensions,
Keyboard
from 'react-native'
import Calendar, CalendarList, Agenda from 'react-native-calendars';
import Map from 'immutable';
import Modal from 'react-native-modal';
import firebase from 'react-native-firebase';
export default class RespondToInquiry extends React.PureComponent
constructor()
super()
this.state =
_markedDates: ,
//_selectedDay: new Date().dateString,
modalVisible: false,
message: 'Hi, I would like to rent an item from you.',
rentButtonBackground: '#6de3dc',
datesArray: []
this.onDayPress = this.onDayPress.bind(this)
/*initialState =
[new Date()]: 'selected': false,
customStyles:
container:
backgroundColor: '#6de3dc',
,
text:
color: 'white',
fontWeight: 'bold'
,
,
*/
showCalendar = () =>
return (
<Calendar
style=
borderWidth: 0,
borderRadius: 4,
theme=
todayTextColor: '#6de3dc',
selectedDayBackgroundColor: '#6de3dc',
markingType='custom'
markedDates=this.state._markedDates
// Initially visible month. Default = Date()
// Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
minDate=new Date()
// Maximum date that can be selected, dates after maxDate will be grayed out. Default = undefined
// Handler which gets executed on day press. Default = undefined
onDayPress=day => this.onDayPress(day)
// Handler which gets executed on day long press. Default = undefined
onDayLongPress=day =>
console.log('selected day', day)
// Month format in calendar title. Formatting values: http://arshaw.com/xdate/#Formatting
monthFormat='MMM d, yyyy'
// Handler which gets executed when visible month changes in calendar. Default = undefined
onMonthChange=month =>
console.log('month changed', month)
// Hide month navigation arrows. Default = false
//hideArrows=true
// Replace default arrows with custom ones (direction can be 'left' or 'right')
//renderArrow=(direction) => (<Arrow />)
// Do not show days of other months in month page. Default = false
hideExtraDays=true
// If hideArrows=false and hideExtraDays=false do not switch month when tapping on greyed out
// day from another month that is visible in calendar page. Default = false
//disableMonthChange=true
// If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
firstDay=0
// Hide day names. Default = false
//hideDayNames=true
// Show week numbers to the left. Default = false
//showWeekNumbers=true
// Handler which gets executed when press arrow icon left. It receive a callback can go back month
onPressArrowLeft=substractMonth => substractMonth()
// Handler which gets executed when press arrow icon left. It receive a callback can go next month
onPressArrowRight=addMonth => addMonth()
/>
)
onDayPress = (day) =>
const _selectedDay = day.dateString;
let marked = true;
if (this.state._markedDates[_selectedDay])
// Already in marked dates, so reverse current marked state
marked = !this.state._markedDates[_selectedDay].selected;
console.log('marked:', marked);
// Create a new object using object property spread since it should be immutable
// Reading: https://davidwalsh.name/merge-objects
const updatedMarkedDates = ...this.state._markedDates, ... [_selectedDay]: 'selected': marked,
customStyles:
container:
backgroundColor: '#6de3dc',
,
text:
color: 'white',
fontWeight: 'bold'
,
,
// Triggers component to render again, picking up the new state
this.setState( _markedDates: updatedMarkedDates , () =>
console.log('updatedMarkedDates:', this.state._markedDates);
);
else
// Create a new object using object property spread since it should be immutable
// Reading: https://davidwalsh.name/merge-objects
const updatedMarkedDates = ...this.state._markedDates, ... [_selectedDay]: 'selected': true,
customStyles:
container:
backgroundColor: '#6de3dc',
,
text:
color: 'white',
fontWeight: 'bold'
,
,
// Triggers component to render again, picking up the new state
this.setState( _markedDates: updatedMarkedDates , () =>
console.log('updatedMarkedDates:', this.state._markedDates);
);
waitToStoreDates = () => new Promise((resolve) =>
let x = 0;
let datesArray = [];
for(date in this.state._markedDates)
console.log("Date Object: ",date);
if(this.state._markedDates[date].selected)
datesArray.push(date);
x++;
if(x == Object.keys(this.state._markedDates).length)
console.log("x:",x);
console.log('datesArray in waitToStoreDates:', datesArray);
this.state.datesArray = datesArray;
resolve();
)
async processMarkedDates()
await this.waitToStoreDates();
setModalVisible(visible)
this.setState( modalVisible: visible )
componentDidUpdate(prevProps, prevState, snapshot)
console.log('componentDidUpdate in InitiateRent:', this.props, prevProps, prevState, snapshot)
_renderModalContent = () => (
<TouchableWithoutFeedback onPress=() => console.log('tapped')>
<View
style=
paddingTop: 5,
paddingBottom: 10,
paddingLeft: 10,
paddingRight: 10,
marginTop: 0,
flex: 1,
width: Dimensions.get('window').width
>
<View style= flexDirection: 'column', justifyContent: 'space-between', flex: 1 >
<View style= flexDirection: 'column', flex: 1 >
<Text
style=
flex: 0,
width: Dimensions.get('window').width,
color: 'white',
fontWeight: '700',
marginBottom: 5,
>
Date(s) Needed:
</Text>
this.showCalendar()
</View>
<View style= flexDirection: 'column', flex: 0.2, marginBottom: 10 >
<TextInput
style=
width: 280,
flex: 1,
borderColor: 'gray',
borderWidth: 1,
backgroundColor: '#ffffff',
paddingLeft: 5,
borderRadius: 4,
onChangeText=text => this.setState( message: text )
value=this.state.message
multiline=true
numberOfLines=2
/>
</View>
<View style= flex: 0.1, borderRadius: 4, borderWidth: 0 >
<TouchableOpacity
activeOpacity=1
style=
backgroundColor: this.state.rentButtonBackground,
flex: 1,
justifyContent: 'center',
alignItems: 'center',
width: 280,
borderRadius: 4,
borderWidth: 0,
onPress=() =>
this.setState( rentButtonBackground: '#94ebe6' )
setTimeout(() =>
this.setState( rentButtonBackground: '#6de3dc' )
let timestamp = new Date().getTime().toString();
this.processMarkedDates();
console.log("this.state.datesArray", this.state.datesArray);
dataChat =
"title": "Rental Inquiry",
"lastMessage": this.state.message,
"timestamp": timestamp
dataMessage =
dataMessage[timestamp] =
"name": "eamon",
"message": this.state.message,
"timestamp": timestamp,
"dates": JSON.stringify(this.state.datesArray)
;
this.sendRentMessage(dataChat, dataMessage, timestamp)
this.setModalVisible(false)
, 1)
>
<Text
style=
backgroundColor: this.state.rentButtonBackground,
textAlign: 'center',
color: 'white',
fontWeight: '900',
fontSize: 18,
borderRadius: 4,
borderWidth: 0,
>
SEND
</Text>
</TouchableOpacity>
</View>
</View>
</View>
</TouchableWithoutFeedback>
);
componentDidMount()
firebase.messaging()
.hasPermission()
.then(enabled =>
if (!enabled)
console.log('permissions disabled');
this._getPermission();
console.log('permissions enabled');
firebase.messaging().subscribeToTopic('all').catch((error) => alert(error));
firebase.messaging().getToken()
.then(fcmToken =>
if (fcmToken)
//USE THIS FOR INDIVIDUAL DEVICE MESSAGES?
console.log(fcmToken);
else
alert("User doesn't have a token yet");
).catch((error) =>
alert(error);
);
).then(() =>
).catch((error) => alert(error));
_getPermission = () =>
firebase.messaging()
.requestPermission()
.catch(error =>
// User has rejected permissions
// this._getPermission();
Alert.alert(
'ERROR',
"You must enable push notifications for the messaging system to work! If you don't you won't be able to use SnagIt! Please enable notificaitons in your phone - go to: Settings > Notifications > SnagIt.",
[
text: 'OK', onPress: () => console.log('OK Pressed'),
],
cancelable: false
)
);
sendRentMessage(dataChat, dataMessage, timestamp)
// Add a new document with a generated id. //user-user //send generated ID and then change to message id in cloud
/*let addChat = firebase.firestore().collection('chats').doc(timestamp);
// Add a new document with a generated id. //user-user //send generated ID and then change to message id in cloud
let addMessage = firebase.firestore().collection('messages').doc(timestamp);
// Set the 'capital' field of the city
addChat.update(dataChat).then(() =>
// Set the 'capital' field of the city
addMessage.update(dataMessage).catch((error) =>
//alert(error);
addMessage.set(dataMessage).catch((error) =>
alert(error);
);
);
).catch((error) =>
//alert(error);
addChat.set(dataChat).catch((error) =>
alert(error);
).then(() =>
addMessage.update(dataMessage).catch((error) =>
//alert(error);
addMessage.set(dataMessage).catch((error) =>
alert(error);
);
);
)
);*/
render()
return (
<View style=flex: 1>
<Modal
animationType="slide"
transparent=true
visible=this.state.modalVisible
onBackdropPress =() => console.log("backdrop pressed"); this.setModalVisible(false)>
this._renderModalContent()
</Modal>
</View>
)
对于控制台输出,我看到:
this.state.showRespondTo: – true
所以我知道条件正在更改为它应该呈现组件的状态。我还看到屏幕的一半(组件应该在哪里)作为空白/白色背景。这是因为我的flexbox
设置方式是我想要的行为。但是应该呈现的元素没有显示出来。 didFocus
侦听器上的条件更改状态,如下所示:
componentDidMount()
this._sub = this.props.navigation.addListener(
'didFocus',
() =>
if(this.props.navigation.getParam('data', '') != '')
console.log('showRespondTo fired.');
this.setState(showRespondTo: true);
);
....
为什么我的InitiateRent
组件不渲染空白/白色区域所在的位置(见下图)?
【问题讨论】:
【参考方案1】:有点傻,this.state.modalVisible
最初设置为 false,所以模态框没有出现。
【讨论】:
以上是关于React Native - 无法使用条件渲染视图的主要内容,如果未能解决你的问题,请参考以下文章
Native Base Picker [React Native] 项目的条件渲染
如何在 React Native 中使用 switch 进行条件渲染?