使用setState在状态更改时React组件未重新呈现

时间:2019-05-27 05:56:53

标签: react-native

我有一个带有按钮的HomeScreen组件。我试图在单击按钮时弹出一个modelview(单独的组件,即PopUpView)。我在PopUpView中将其可见性作为prop(isVisible)发送。单击按钮时,我试图将状态值popUpIsVisible从false更改为true。希望这将重新渲染并弹出我的模型视图(请注意,如果我显式传递true,这将很好地工作)。但是,通过状态更改,看起来好像没有调用render函数并且没有显示popUp。感谢您的提前帮助

import React from 'react';
import { View, StyleSheet, Text, Button, TouchableHighlight, Alert, Dimensions} from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import PopUpView from './src/PopUpView';


class HomeScreen extends React.Component {

  constructor(props) {
      super(props);
      this.state = {
        popUpIsVisible: false,
      };
    }

  setPopUpIsVisible(isVisible){
    this.setState({popUpIsVisible: isVisible });
  }

  render() {
    this.setPopUpIsVisible = this.setPopUpIsVisible.bind(this);
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor:"blue" }}>
        <Text>Home Screen</Text>
          <PopUpView isVisible={this.state.popUpIsVisible}/>
          <Button onPress={() => {this.setPopUpIsVisible(true)}}  title="Open PopUp Screen"/>
      </View>
    );
  }
}

const RootStack = createStackNavigator(
  {
    Home: HomeScreen
  },
  {
    initialRouteName: 'Home',
  }
);

const AppContainer = createAppContainer(RootStack);

export default class App extends React.Component {
  render() {
    return <AppContainer />;
  }
}

PopUpView.js

import React from 'react';
import { View, Modal,StyleSheet, Text, TouchableOpacity, Dimensions} from 'react-native';
import { TabView, TabBar,SceneMap } from 'react-native-tab-view';
import Icon from 'react-native-vector-icons/SimpleLineIcons';

const FirstRoute = () => (
  <View style={{ flex: 1, backgroundColor: '#ff4081' }} />
);
const SecondRoute = () => (
  <View style={{ flex: 1, backgroundColor: '#673ab7' }} />
);
const ThirdRoute = () => (
  <View style={{ flex: 1, backgroundColor: '#673ab7' }} />
);


export default class PopUpView extends React.Component {
  constructor(props) {
      super(props);
      this.state = {
          modalVisible:this.props.isVisible,
          index: 0,
          routes: [
            { key: 'first', title: 'HIGHLIGHTS' },
            { key: 'second', title: 'AMENITIES' },
            { key: 'third', title: 'FACILITIES' },
          ],
        };
    }
    setModalVisible(visible) {
      this.setState({modalVisible: visible});
    }

renderHeader = props => <TabBar
    {...props}
    indicatorStyle={{backgroundColor: 'red'}}
    tabStyle={styles.bubble}
    labelStyle={styles.noLabel}
/>;

  render() {
      return (
      <Modal
          animationType="slide"
          transparent={true}
          visible={this.state.modalVisible}
          onRequestClose={() => {
            Alert.alert('Modal has been closed.');
          }}>
          <View style={styles.container}>
            <View style={styles.navBar}>
              <Text style={styles.navBarTitle}>Test</Text>
              <TouchableOpacity
                onPress={() => {
                  this.setModalVisible(!this.state.modalVisible);
                }}>
              <Icon style={styles.closeButton} name="close" size={35} color="grey" />
              </TouchableOpacity>
            </View>
            <TabView
              navigationState={this.state}
              renderScene={SceneMap({
                first: FirstRoute,
                second: SecondRoute,
                third: ThirdRoute,
                })}
              onIndexChange={index => this.setState({ index })}
              initialLayout={{ width: Dimensions.get('window').width }}
              renderTabBar={props =>
                      <TabBar
                          {...props}
                          style={{ backgroundColor: 'white' }}
                          indicatorStyle={{backgroundColor: 'black'}}
                          tabStyle={styles.bubble}
                          labelStyle={styles.label}
                      />
                  }
              />
          </View>
        </Modal>
      );
    }
}

const styles = StyleSheet.create({
  container: {
    flex:1,
    margin: 50,
    marginLeft: 20,
    marginRight: 20,
    marginBottom: 20,
    backgroundColor: "white",
    borderWidth: 1,
    borderColor: "grey",
    flexDirection: 'column'
  },
  navBar:{
    height:70,
    justifyContent: 'space-between',
    alignItems: 'center',
    flexDirection: 'row',
    borderBottomColor: 'lightgrey',
    borderBottomWidth: 1,
  },
  navBarTitle:{
    fontSize: 25,
    fontFamily: 'Optima',
    paddingLeft:15,
  },
  closeButton:{
    paddingRight:12,
  },
  label: {
        color: 'black'
    }
})

2 个答案:

答案 0 :(得分:1)

代码的问题是您正在使用PopUpView内部的状态,而更改外部prop时该状态不会更改。要解决此问题,您应该使用componentwillreceiveprops并相应地更新状态。

componentWillReceiveProps(nextProps){
  if(this.props.isVisible!=nextProps.isVisible){
    this.setState({modalVisible:nextProps.isVisible})
  }
}

更好的方法是将this.props.isVisible用作模型的visible道具。 在这种情况下,您将必须将一个函数作为道具传递给popupview,这会将popUpIsVisible设置为false。 像下面这样

 <PopUpView isVisible={this.state.popUpIsVisible} 
            onDismiss={()=>{this.setState({popUpIsVisible:false})}}/>

您可以将子对象中的onDismiss称为

<Modal visible={this.props.isVisible}>
<TouchableHighlight
    onPress={() => {
      this.props.onDismiss();
    }}>
 <Text>Hide Modal</Text>
</TouchableHighlight>
</Modal>

第二种方法更好,因为孩子的可见度由父母控制。

答案 1 :(得分:0)

在状态定义后将以下行添加到构造函数中

this.setPopUpIsVisible = this.setPopUpIsVisible.bind(this);