【问题标题】:React native - open multiple modals one after the other inside for loop反应原生 - 在 for 循环中一个接一个地打开多个模式
【发布时间】:2019-07-31 09:10:22
【问题描述】:

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

提供数据的 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>
        }
    )
}

目前所有的Modal同时打开。单击收集按钮后如何依次打开它们?

【问题讨论】:

    标签: javascript reactjs react-native for-loop react-modal


    【解决方案1】:

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

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

    您应该跟踪活动模式的 index,而不是 showAchievementModal。因此,在您从 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。如果您碰巧需要按某个值/优先级对成就进行排序,并且用户可以检索其成就的多个页面,则可能会导致渲染错误的组件。

    【讨论】:

    • 感谢您的回复!像魅力一样工作。我为其他人添加了我的代码的更新版本
    • 很高兴我能帮上忙。另外,我更新了我的答案:我已将 key prop 移至 Modal 组件,并链接了一篇关于使用映射索引作为 key 的危险的文章
    • 还有一件事。关闭最后一个模式(数组中的最后一个成就)时 - 你如何将 activeModalIndex 重置为 0 ?
    • 你想完成什么?关闭最后一个模态后将 activeModalIndex 重置为 0 将再次显示第一个模态。如果您只需要关闭最后一个,则无需重置任何内容。如果您有 3 个成就,您将拥有 3 个模态 - 模态 0、模态 1 和模态 2。一旦关闭最后一个 - 模态 2,活动索引将从 2 变为 3,并且由于您没有模态 3 来检查activeIndex === 3,什么都不会被渲染。
    • 但是,如果你需要在最后一个模态关闭时设置一个标志,你可以做 closeModal = () => { const maxIndex = this.state.achievements.length - 1; const currentIndex = this.state.activeModalIndex; const lastModalClosed = currentIndex === maxIndex; // 如果最后一个模态关闭,则将 activeModalIndex 设置为无效值,例如 -1 // 否则,将其递增 const newIndex = isLastModal ? -1:当前索引 + 1; this.setState(previousState => ({ activeModalIndex: newIndex, lastModalClosed, })) }
    【解决方案2】:

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

    在构造函数中初始化 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
      })
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-27
      • 2023-01-12
      • 1970-01-01
      • 2019-08-15
      • 1970-01-01
      相关资源
      最近更新 更多