React native - 在 for 循环中一个接一个打开多个模式

React native - open multiple modals one after the other inside for loop

我首先进行 Ajax 调用(对 API),它为我提供了一些数据,成就列表(objects 数组)。我想遍历这个数组,将第一个成就显示为模式,然后单击按钮关闭模式,然后显示下一个(下一个成就)等等。

Ajax调用提供数据:

getAchievements = () => {
    fetch(url + '/achievements', {
      method: 'get',
      headers: {
        Accept: 'application/json',
        'Content-type': 'application/json'
      }
    })
    .then((data) => data.json())
    .then((data) => {
      this.props.addData({
        achievements: data.achievements
      })

      if(this.props.store.achievements.length > 0) {
        this.setState({
          showAchievementModal: true
        })
      }
    })
    .catch((error) => {
      console.error(error)
    })
}

这里我展示模态:

render() {
    return (
        {this.state.showAchievementModal &&
          <Modal
            animationType={'fade'}
            visible={this.props.store.isModalAchievementVisible}
            >
            {this.props.store.achievements.map((data,index)=>{
                return(
                    <View key={index}>
                        <View style={styles.container}>
                            <Text>{data.title}</Text>
                            <Text>{data.description}</Text>

                            <TouchableOpacity onPress={this.closeModal}>
                                <Text>Collect</Text>
                            </TouchableOpacity>
                        </View>
                  </View>
                )
            })}
          </Modal>
        }
    )
}

目前所有模态框同时打开。点击收藏按钮后如何一个接一个打开?

问题是您的页面上有多个模态框,它们都使用相同的布尔值来检查是否应呈现它们。最初,showAchievementModal 设置为 true,因此所有模态都被渲染。此外,在 showAchievementModal 中将 showAchievementModal 设置为 false 后,它将永久保持 false,因此不会渲染其他模态。

render() {
    return (
        {this.state.showAchievementModal &&
          <Modal
             ...          
          </Modal>
        }
    )
}

而不是 showAchievementModal 你应该跟踪活动模式的 index。因此,在您从 API 获取成就列表后,将 activeModalIndex 设置为 0。用户关闭第一个模态后,在 closeModal 方法中将 activeModalIndex 设置为 1 ,然后设置在第二个模式关闭后它变为 2 等等。

现在,为了让每个模态框对应一个成就,我们必须将成就数组的每个元素映射到一个模态框,并且只有当对应的索引是活动的时才有条件地渲染它。

render() {
    const achievements = this.props.store.achievements;
    const { activeModalIndex } = this.state;

    return achievements.map((data, index) => activeModalIndex === index &&
      <Modal key={index}>
        <View>
          <View style={styles.container}>
            <Text>{data.title}</Text>
            <Text>{data.description}</Text>

            <TouchableOpacity onPress={this.closeModal}>
              <Text>Collect</Text>
            </TouchableOpacity>
          </View>
        </View>
      </Modal>
    )
}

当用户关闭当前活动模态时,只需增加活动模态的索引,下一个模态就会出现,而不是当前模态。如果新增加的值等于或大于数组长度,则不会呈现任何内容,因此在设置新状态之前无需检查最大索引值。

closeModal = () => {   
    this.setState(previousState => ({
      activeModalIndex: previousState.activeModalIndex + 1,
    }))
}

此外,请在呈现列表时阅读有关 the dangers of setting index as key 的内容。如果您碰巧需要按某些 value/priority 排序成就并且用户可以检索他们的多页成就,则可能会导致呈现错误的组件。

这是我的代码的更新版本:

在构造函数中初始化activeModalIndex:

constructor(props) {
  super(props)

  this.state = {
    activeModalIndex: 0
  }
}

获得成就:

getAchievements = () => {
  if(this.props.store.achievements.length > 0) {
    this.setState({
      showAchievementModal: true,
      activeModalIndex: 0,
    })
  }
}

渲染函数:

 render() {
   return this.props.store.achievements.map((data,index) => this.state.activeModalIndex === index &&
     <Modal>
       <View key={index}>
         <View style={styles.container}>
           <Text>{data.title}</Text>
           <Text>{data.description}</Text>

           <TouchableOpacity onPress={this.closeModal}>
             <Text>Collect</Text>
           </TouchableOpacity>
        </View>
      </View>
    </Modal>
  )
}

关闭模式:

closeModal = () => {
  const maxIndex = this.props.store.achievements.length - 1
  const currentIndex = this.state.activeModalIndex
  const isLastModal = currentIndex === maxIndex
  const newIndex = isLastModal? -1: currentIndex +1

  this.setState({
    activeModalIndex: newIndex
  })
}