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 - 无法使用条件渲染视图的主要内容,如果未能解决你的问题,请参考以下文章

React Native 某些样式导致视图无法呈现

Native Base Picker [React Native] 项目的条件渲染

如何在 React Native 中使用 switch 进行条件渲染?

即使设置为 false,使用条件渲染的 React Native 仍然尝试访问状态

React Native 中获取后的条件渲染

React Native 条件渲染不起作用