热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

React中通过数组渲染的组件怎么响应state的更新?

场景描述我在做一个添加用户信息的对话框,用户可能又若干个电话,所以需要自由增删电话输入框。如图:

场景描述

我在做一个添加用户信息的对话框,用户可能又若干个电话,所以需要自由增删电话输入框。
如图:




问题背景

我是在对话框组件的 state 中维护一个数组 telsInput,来存储电话输入框数组。
在 render 函数中直接渲染这个数组 {this.state.telsInput}
当点击添加电话按钮时,触发事件,push 一个输入框组件进该数组。点击删除按钮时,pop 出末尾的输入框。
这样就能满足不同数量的电话需求。

问题描述

我想把电话输入框的值和 state 中的值绑定起来(可控组件),但通过数组渲染的输入框组件的 value 不能响应 state 的变化。
我猜测问题出在下面的代码中



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   /**

    * 点击’添加电话‘按钮时触发,向 state.telsInput 中 push 一个 电话输入框组件

    **/

   addTels = () => {

        // telsInput 数组用于存储电话输入框组件

        let telsInput = this.state.telsInput,

            number = telsInput.length + 2;

        const tel =
                        placeholder={"电话" + number}

                        size="large"

                        key={number}

                        ref={(node) => this['userTels' + number] = node}

                        prefix={}

                        // 在 onChange 事件中获取该输入框的值来更新 state.userTels 对应的值

                        OnChange={(e) => { this.onChange(e, 'tel', number - 1) }}

                        // 我觉得问题出在这里

                        value={this.state.userTels[number - 1]}

                        10px' }}

                    />;

        telsInput.push(tel);

        this.setState({

            telsInput: telsInput,

            removeable: true,

        })

    }

上面代码中组件的 value 属性设置为 {this.state.userTels[number - 1],我感觉这在编译时,这里的 {this.state.userTels[number - 1]} 会直接被替换成对应的字符串。由于初始值为空,所以在 render 函数中直接变为了,value='',所以才导致无法响应 state 中变化。

请问有什么办法可以解决这种情况吗,或者针对这种需求有其他的设计思路吗?

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import React from 'react';

import { Button, Modal, Input, Icon } from 'antd';



class UserDia extends React.Component {

    constructor(props) {

        super(props);

        this.state = {

            modalContain: '',

            visible: false,

            confirmLoading: false,

            userName: props.uname || '',

            userAddr: props.uaddress || '',

            userTels: [],

            telsInput: [],

            removeable: false,

        };

    }

    componentWillReceiveProps(nextProps) {

        this.setState({

            visible: nextProps.visible

        })

    }

    addTels = () => {

        let telsInput = this.state.telsInput,

            number = telsInput.length + 2;

        const tel =
                        placeholder={"电话" + number}

                        size="large"

                        key={number}

                        ref={(node) => this['userTels' + number] = node}

                        prefix={}

                        OnChange={(e) => { this.onChange(e, 'tel', number - 1) }}

                        value={this.state.userTels[number - 1]}

                        10px' }}

                    />;

        telsInput.push(tel);

        this.setState({

            telsInput: telsInput,

            removeable: true,

        })

    }

    removeTel = () => {

        let telsInput = this.state.telsInput,

            removeable = telsInput.length === 1 ? false : true;

        telsInput.pop();

        this.setState({

            telsInput: telsInput,

            removeable: removeable

        });

    }

    showModal = () => {

        this.setState({

            visible: true,

        });

    }

    handleOk = () => {

        this.setState({

            confirmLoading: true,

        });

        setTimeout(() => {

            this.setState({

                visible: false,

                confirmLoading: false,

            });

        }, 2000);

    }

    handleCancel = () => {

        this.setState({

            visible: false,

        });

    }

    OnChange= (e, type, index) => {

        switch (type) {

            case 'name':

                this.setState({ userName: e.target.value });

                break;

            case 'addr':

                this.setState({ userAddr: e.target.value });

                break;

            case 'tel':

                const userTels = this.state.userTels;

                userTels[index] = e.target.value;

                this.setState({ userTels: userTels})

        }

    }

    emitEmpty = (type) => {

        switch (type) {

            case 'name':

                this.userNameInput.focus();

                this.setState({ userName: '' });

                break;

            case 'addr':

                this.userAddr.focus();

                this.setState({ userAddr: '' })

                break;

            case 'tel':

                break;

        }

    }

    render() {

        console.log(this.state.userTels);

        let arr = [, ]

        const { visible, confirmLoading, modalContain, removeable, userName, userAddr, userTels, telsInput } = this.state,

            nameSuffix = userName ? {this.emitEmpty('name')}} /> : null,

            addrSuffix= userAddr? {this.emitEmpty('addr')}} /> : null;

        return (

           
                maskClosable={false}

                visible={visible}

                OnOk={this.handleOk}

                cOnfirmLoading={confirmLoading}

                OnCancel={this.handleCancel}

            >

               


                   
                        placeholder="用户名"

                        size="large"

                        value={userName}

                        suffix={nameSuffix}

                        prefix={}

                        ref={(node) => {this.userNameInput = node}}

                        OnChange={(e) => { this.onChange(e, 'name') }}

                        10px' }}

                    />

                   
                        placeholder="地址"

                        size="large"

                        value={userAddr}

                        suffix={addrSuffix}

                        prefix={}

                        ref={(node) => {this.userAddr = node}}

                        OnChange={(e) => { this.onChange(e, 'addr') }}

                        10px' }}

                    />

                   
                        placeholder="电话1"

                        size="large"

                        value={userTels[0]}

                        prefix={}

                        OnChange={(e) => { this.onChange(e, 'tel', 0) }}

                    />

                   

                        {telsInput}

                   


                   


                         

                       

                   


               


           


        )

    }

}



export default UserDia;



   



推荐阅读
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
  • 本文讨论了将HashRouter改为Router后,页面全部变为空白页且没有报错的问题。作者提到了在实际部署中需要在服务端进行配置以避免刷新404的问题,并分享了route/index.js中hash模式的配置。文章还提到了在vueJs项目中遇到过类似的问题。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • 本文介绍了如何使用elementui分页组件进行分页功能的改写,只需一行代码即可调用。通过封装分页组件,避免在每个页面都写跳转请求的重复代码。详细的代码示例和使用方法在正文中给出。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • 先看看ElementUI里关于el-table的template数据结构:<template><el-table:datatableData><e ... [详细]
  • 带添加按钮的GridView,item的删除事件
    先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
author-avatar
成就未来7368
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有