首页 > 解决方案 > 从孩子改变父母的状态时,为什么父母不再渲染?

问题描述

我有一个父类,它将一个调用的函数传递editClassInfo给子类。此函数绑定到父级,并且在调用时会不可变地更改父级的状态。但是,父级不会再次渲染,而是必须从父级内部设置状态。

具体来说,问题出在模态组件上textInput,当文本更改时,它会设置父屏幕的状态。但是,当模态框关闭时,即使状态发生了变化,屏幕的状态也不会立即更新。相反,this.setState()必须调用另一个才能再次进行渲染。

这是问题的图片参考: https ://imgur.com/a/oCHRTIu

这是代码:

这是父组件。

export default class Classes extends Component {
  static navigationOptions = {
    title: 'Classes'
  };

  constructor() {
    super();

    this.state = {
      numObjects: 3.,
      classes: [
        {
          className: "Math",
          teacherName: "Someone",
        },
        {
          className: "Science",
          teacherName: "Someone",
        },
        {
          className: "Art",
          teacherName: "Someone",
        }
      ]
    };

    this.editClassInfo = this.editClassInfo.bind(this);
  }

  editClassInfo(index, infoType, value) {
    let newClass = this.state.classes;
    switch (infoType) {
      case 'className':
        newClass[index].className = value;
        break;
      case 'teacherName':
        newClass[index].teacherName = value;
        break;
    }
    this.setState({classes: newClass});
  }

  addClass(name, name2) {
    let newClass = this.state.classes.concat({className: name, teacherName: name2});
    this.setState({classes: newClass});
  }

  loadClasses = () => {
    this.setState({
        numObjects: this.state.numObjects * 2,
    })
  }

  render(){
    const classData = this.state.classes;
    console.log(this.state.classes[0]);
    return (
      <View style={styles.container}>
        <TopBar title='Classes'/>
        <View style={styles.classHeader}>
          <Text style={styles.currentClasses}> CURRENT CLASSES </Text>
          <TouchableOpacity onPress={() => {this.addClass('World History', 'Someone')}}>
            <Image
              style = {styles.addClass}
              source={require('../resources/addClass.png')}
            />
          </TouchableOpacity>
        </View>
        <FlatList
          data = { classData }
          onEndReached = {this.loadClasses}
          keyExtractor = {(item, index) => index.toString()}
          initialNumtoRender = {3}
          renderItem = {({item}) =>
            <ClassBox
              index={this.state.classes.indexOf(item)}
              editClassInfo ={this.editClassInfo}
              className={item.className}
              teacherName={item.teacherName}
            />
          }
        />
      </View>
    );
  }
}

我传递editClassInfo到一个名为ClassBox

export default class ClassBox extends Component {
  static propTypes = {
    className: PropTypes.string.isRequired,
    teacherName: PropTypes.string.isRequired,
    index: PropTypes.number.isRequired
  };

  constructor(props) {
    super(props);

    this.state = {
      isVisible: false,
    };

    this.modalVisible = this.modalVisible.bind(this);
  }

  modalVisible(visible) {
    this.setState({isVisible: visible});
  }

  render(){
    return(
      <View>
        <ClassEdit
          index={this.props.index}
          editClassInfo={this.props.editClassInfo}
          isVisible={this.state.isVisible}
          modalClose={this.modalVisible}
          className={this.props.className}
          teacherName={this.props.teacherName}
        />
        <TouchableOpacity onPress={() => {this.modalVisible(true)}}>
          <View style={styles.container}>
            <Image
              source={{uri: 'http://via.placeholder.com/50x50'}}
              style={styles.classImage}
            />
            <View style={styles.classInfo}>
              <Text style={styles.className}>
                {this.props.className}
              </Text>
              <Text style={styles.teacherName}>
                {this.props.teacherName}
              </Text>
            </View>
          </View>
        </TouchableOpacity>
      </View>
    )
  }
}

该组件包含 Child Modal ClassEdit

export default class ClassEdit extends Component {
  static propTypes = {
    index: PropTypes.number.isRequired,
    isVisible: PropTypes.bool.isRequired,
    className: PropTypes.string.isRequired,
    teacherName: PropTypes.string.isRequired
  }

  render() {
    return(
      <Modal
        animationType="none"
        transparent={false}
        visible={this.props.isVisible}
      >
        <View style={styles.container}>
          <View style={styles.closeTop}>
            <TouchableOpacity onPress={() => {
              this.props.modalClose(false);
            }}>
              <Image
                style={styles.closeIcon}
                source={require('../resources/close.png')}
              />
            </TouchableOpacity>
          </View>
          <View style={styles.classInfo}>
            <Image
              source={{uri: 'http://via.placeholder.com/150x150'}}
              style={styles.classImage}
            />
            <TextInput
              style={styles.className}
              placeholder='Class Name'
              value={this.props.className}
              onChangeText = {(className) => {this.props.editClassInfo(this.props.index, 'className', className)}}
            />
            <TextInput
              style={styles.teacherName}
              placeholder='Teacher Name'
              value={this.props.teacherName}
              onChangeText = {(teacherName) => {this.props.editClassInfo(this.props.index, 'teacherName', teacherName)}}
            />
          </View>
        </View>
      </Modal>
    );
  }
}

正是在最后一个称为ClassEdit父状态的组件中,当模式关闭时,更新的状态是看不到的,而是必须调用addClass来触发它。

我对 react-native 有点陌生,所以我的代码可能不是最好的,问题可能非常简单,但任何帮助都将不胜感激。

标签: javascriptiosreactjsclassreact-native

解决方案


let newClass = this.state.classes;创建对实际classes状态的引用,然后您将对其进行变异。

要以不可变的方式创建一个新数组,您可以这样做:

ES6:

let newClass = [...this.state.classes];

ES5:

let newClass = [].concat(this.state.classes);

推荐阅读