【问题标题】:When changing the parent's state from a child, why does the parent not render again?从孩子改变父母的状态时,为什么父母不再渲染?
【发布时间】:2018-07-03 03:13:37
【问题描述】:

我有一个父类,它将一个名为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>
    )
  }
}

此组件包含子模态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 有点陌生,所以我的代码可能不是最好的,问题可能非常简单,但我们将不胜感激。

【问题讨论】:

标签: javascript ios reactjs class react-native


【解决方案1】:

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

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

ES6:

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

ES5:

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

【讨论】:

  • 谢谢。这是我的问题的一种解决方案,而且可能是更好的解决方案,因为当我尝试不可变地更新我的状态数组时,我犯了一个错误。我使用了let newClass = this.state.classes.slice(),但我认为它完成了同样的事情(如果我错了,请纠正我)。但是,另一种解决方案是在看到您的答案之前我自己发现的一个解决方案是为 FlatList 组件提供一个 extraData 道具,这是一个状态值,每当需要渲染时,函数都会“刷新”该状态值。事后看来,您的解决方案更简洁,语法更正确。 :D
猜你喜欢
  • 1970-01-01
  • 2016-12-18
  • 1970-01-01
  • 2015-09-05
  • 2016-07-07
  • 2018-06-29
  • 1970-01-01
  • 2021-01-21
  • 1970-01-01
相关资源
最近更新 更多