【问题标题】:React native - dynamically add a view onPressReact native - 动态添加视图 onPress
【发布时间】:2017-02-06 22:37:28
【问题描述】:

我有一个包含按钮的视图 - onPress 它会打开一个显示联系人列表的模式。

  1. 任何这些联系人的 onPress(pickContact 函数)我想动态地将新视图添加到 _renderAddFriendTile(按钮上方)。

  2. 另外,理想情况下,每个联系人姓名旁边的“添加”图标(在模式中)应该更新(“删除”图标),无论它们是否存在于 _renderAddFriendTile 视图中。

最好的方法是什么?

[更新代码]

 import React, {Component} from 'react'
    import {
        Text,
        View,
        ListView,
        ScrollView,
        StyleSheet,
        Image,
        TouchableHighlight,
        TextInput,
        Modal,
    } from 'react-native'


    const friends = new ListView.DataSource({
        rowHasChanged: (r1, r2) => r1 !== r2
    }).cloneWithRows([
        {
            id: 1,
            firstname: 'name01',
            surname: 'surname01',
            image: require('../images/friends/avatar-friend-01.png')
        },
        {
            id: 2,
            firstname: 'name02',
            surname: 'surname02',
            image: require('../images/friends/avatar-friend-02.png')
        },
        {
            id: 3,
            firstname: 'name03',
            surname: 'surname03',
            image: require('../images/friends/avatar-friend-03.png')
        },
        {
            id: 4,
            firstname: 'name04',
            surname: 'surname04',
            image: require('../images/friends/avatar-friend-04.png')
        },
    ])


    class AppView extends Component {
        state = {
            isModalVisible: false,
            contactPicked: [],
            isFriendAdded: false,
        }

        setModalVisible = visible => {
            this.setState({isModalVisible: visible})
        }

        pickContact = (friend) => {
            if(this.state.contactPicked.indexOf(friend) < 0){
                this.setState({
                    contactPicked: [ ...this.state.contactPicked, friend ],

                })
            }

            if(this.state.contactPicked.indexOf(friend) >= 0){
                this.setState({isFriendAdded: true})
            }
        }

        _renderAddFriendTile = () => {
            return(
                <View style={{flex: 1}}>
                    <View style={[styles.step, styles.stepAddFriend]}>
                        <TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
                            <View style={styles.addFriendButton}>
                                <Text style={styles.addFriendButtonText}>Add a friend</Text>
                            </View>
                        </TouchableHighlight>
                    </View>
                </View>
            )
        }

        render(){
            return (
                <ScrollView style={styles.container}>
                    <Modal
                        animationType={'fade'}
                        transparent={true}
                        visible={this.state.isModalVisible}
                    >
                        <View style={styles.addFriendModalContainer}>
                            <View style={styles.addFriendModal}>
                                <TouchableHighlight onPress={() => {this.setModalVisible(false)}}>
                                    <View>
                                        <Text style={{textAlign:'right'}}>Close</Text>
                                    </View>
                                </TouchableHighlight>
                                <ListView
                                    dataSource={friends}
                                    renderRow={(friend) => {
                                        return (
                                            <TouchableHighlight onPress={() => {this.pickContact()}}>
                                                <View style={[styles.row, styles.friendRow]}>
                                                    <Image source={friend.image} style={styles.friendIcon}></Image>
                                                    <Text style={styles.name}>{friend.firstname} </Text>
                                                    <Text style={styles.name}>{friend.surname}</Text>

                                                    <View style={styles.pickContainer}>
                                                        <View style={styles.pickWrapper}>
                                                            <View style={this.state.isFriendAdded ? [styles.buttonActive,styles.buttonSmall]: [styles.buttonInactive,styles.buttonSmall]}>
                                                                <Image source={this.state.isFriendAdded ? require('../images/button-active.png'): require('../images/button-inactive.png')} style={styles.buttonIcon}></Image>
                                                            </View>
                                                        </View>
                                                    </View>
                                                </View>
                                            </TouchableHighlight>
                                        )
                                    }}
                                />
                            </View>
                        </View>
                    </Modal>

                    {this._renderAddFriendTile()}
                </ScrollView>
            )
        }
    }

    export default AppView

【问题讨论】:

    标签: javascript ios listview reactjs react-native


    【解决方案1】:

    由于您需要动态更新某些内容,这清楚地表明您需要利用本地状态对数据进行建模。 (撇开你没有使用像 Redux 这样的状态库管理)

    state = {
        isModalVisible: false,
        contactPicked: null,
    }
    

    您的pickContact 函数需要来自 listView 的好友数据,因此您需要在选择行的情况下调用它:

     <TouchableHighlight onPress={() => {this.pickContact(friend)}}>
    

    然后在您的 pickContact 函数中,使用新的 contactsPicked 数据模型更新您的 UI

    pickContact = (friend) => {
        this.setState({
          contactPicked: friend,
        });
    }
    

    这将使您的组件重新渲染,并且您可以在 _renderAddFriendTile 中放置一些逻辑来渲染一些额外的 UI(视图、文本..),因为 this.state.contactPicked 上存在值您可以使用以下内容:

    _renderAddFriendTile = () => {
        return(
            <View style={{flex: 1}}>
                {this.state.contactPicked && (
                  <View>
                    <Text>{contactPicked.firstName}<Text>
                  </View>
                )}
                <View style={[styles.step, styles.stepAddFriend]}>
                    <TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
                        <View style={styles.addFriendButton}>
                            <Text style={styles.addFriendButtonText}>Add a friend</Text>
                        </View>
                    </TouchableHighlight>
                </View>
            </View>
        )
    }
    

    请注意,您现在保留了所选联系人的名字,因此第 2 点应该很容易解决。就在 ListView 的 renderRow 内部,如果 friend.firstname === this.state.contactPicked.firstname 则呈现不同的图标

    注意:不要依赖名字来进行这种检查,因为你可以有重复的,这会失败。最好的解决方案是为您的列表模型提供每个联系人唯一的 id 属性,并使用该 id 属性来检查上述逻辑。

    旁注

    {this.state.contactPicked &amp;&amp; (&lt;View&gt;&lt;Text&gt;Some text&lt;/Text&gt;&lt;/View)} 部分正在使用条件渲染。 &amp;&amp; 充当 if 所以如果this.state.contactPicked 是真实的,它将呈现视图,否则它将不呈现任何内容(虚假和null 值被反应解释为“没有呈现")。

    当然,如果你想动态渲染多个项目,你的状态模型应该是一个数组,即contactsPicked,最初是空的。每次选择联系人时,都会将新的联系人对象添加到数组中。然后在_renderAddFriendTile 中你可以use map 动态渲染多个组件。我认为你不需要ListView,除非你想要一个单独的可滚动列表。

    _renderAddFriendTile = () => {
        return(
            <View style={{flex: 1}}>
                {this.state.contactsPicked.length && (
                  <View>
                    {this.state.contactsPicked.map(contact => (
                      <Text>{contact.firstName}</Text>
                    )}
                  </View>
                )}
                <View style={[styles.step, styles.stepAddFriend]}>
                    <TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
                        <View style={styles.addFriendButton}>
                            <Text style={styles.addFriendButtonText}>Add a friend</Text>
                        </View>
                    </TouchableHighlight>
                </View>
            </View>
        )
    }
    

    【讨论】:

    • 感谢您的评论。您能否解释一下您创建视图的部分 ({this.state.contactPicked && ()}) 吗?另外,如果我想为每个按下的联系人添加/增加一个新行怎么办?
    • 我添加了一个 Side Notes 部分来解决这些问题,希望对您有所帮助:)
    • 你有没有机会使用数组和映射来更新你的代码(我猜它会使用 ListView)?
    • 太好了,我会试试的。不需要对pickContact() 中的setState 进行更改?
    • 是的,现在您的模型将是一个数组。每次调用 pickContact 时,您都需要推送新元素(不改变您的模型)。如果您使用 ES6 返回一个新数组,请使用 concat 或扩展运算符,例如 [ ...this.state.contactsPicked, friend ]。如果答案对您有用,如果您也可以投票,我将不胜感激
    猜你喜欢
    • 2018-07-30
    • 2021-05-12
    • 2018-02-28
    • 1970-01-01
    • 2019-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    相关资源
    最近更新 更多