element下拉组件多选+异步搜索的坑————diff算法

这是我当时的代码,我使用了index作为key,当时的场景是这样的:
1.第一次我选择了张晓宇,它这时位于列表第三
2.我搜索"张"这个字,并向后端发送请求重新获取数据渲染列表
3.此时张晓宇位于第一位,蓝的勾选的位置也在第一位,但是可以观察input框此时第一位的名字(lable)是重新获取数据后排位第三的张*鹏,而并非张晓宇。
解决方式像下面这串代码一样绑定唯一值就可以了,造成这样的原因我猜测是diff算法的原因.

  • :key=“iabilityManItem.id”

在这里插入图片描述

 <el-form-item label="责任人">
            <el-select v-model="form.liabilityMan" placeholder="请选择" multiple filterable remote :remote-method="findUserByStatus" value-key="name" :disabled="!isEdit">
              <el-option
                v-for="(liabilityManItem,liabilityManIndex) in liabilityManList"
                :key="'liabilityManList'+liabilityManIndex"
                :label="liabilityManItem.name"
                :value="liabilityManItem.value"
              />
            </el-select>
          </el-form-item>

DOM的diffing算法

  • 我们操作数据时不是直接将数据挂在DOM上,而是现在生成的虚拟DOM上进行比较,例如下图对比03是新加的,之前没有的,那么就将03映射成新的真实DOM

在这里插入图片描述

1.1如何证明?

  • 这里时间是实时改变的,但是在input框输入的值并没有被刷掉,哪怕在h1标签内再套标签也不会被刷掉,因为是深层对比,
    <script type="text/babel">
        class Demo extends React.Component {
            state = { time: new Date() }
            componentDidMount() {
                setInterval(() => {
                    this.setState({ time: new Date() })
                }, 1000)
            }
            render() {
                return (
                    <div>
                        <input type="text" />
                        <h1>{this.state.time.toTimeString()}</h1>
                    </div>
                )
            }
        }
        ReactDOM.render(<Demo />, document.getElementById('text'))
    </script>

在这里插入图片描述

1.2key

1.2.1react/vue中的key有什么作用?(key的内部原理是什么?)
  • 简单的说:Key是虚拟DOM对象的标识,在更新显示时Key起着极其重要的作用.
  • 详细的说:当状态中的数据发生变化时,react会根据新数据生成新的虚拟DOM,随后React进行新虚拟DOM旧虚拟DOM的diff比较,比较规则如下:
    a.旧数据DOM中找到了与新虚拟DOM相同的Key:
    1.若虚拟DOM中内容没变,直接使用之前的真实DOM
    2.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
    b.旧虚拟DOM中未找到与新虚拟DOM相同的Key
  1. 根据数据创建新的真实DOM,随后渲染到页面
1.2.2 为什么遍历列表时,key最好不要用index?
  • 若对数据进行:逆序添加、逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新==>界面效果没问题,但效率低
  • 如果结构中还包含输入类的DOM,会产生错误DOM更新==>界面有问题
  • 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的
    <script type="text/babel">
        /**
         * 慢动作回放
         * 初始数据:
         * { name: '兰博基尼', num: 1000, id: 1 }
         * { name: '拖拉机', num: 2000, id: 2 }
         * 
         * 初始虚拟DOM:
         * <li key=0>兰博基尼---1000</li>
         * <li key=1>拖拉机---2000</li>
         * 
         * 更新后数据
         * { name: '玛莎拉蒂', num: 3000, id: 3 }
         * { name: '兰博基尼', num: 1000, id: 1 }
         * { name: '拖拉机', num: 2000, id: 2 }
         * 
         * 更新数据后的虚拟DOM
         * <li key=0>玛莎拉蒂---3000</li>
         * <li key=1>兰博基尼---1000</li>
         * <li key=2>拖拉机---2000</li>
        */
        class Demo extends React.Component {
            state = { car: [{ name: '兰博基尼', num: 1000, id: 1 }, { name: '拖拉机', num: 2000, id: 2 }] }
            add = (() => {
                const car = { name: "玛莎拉蒂", num: 3000, id: this.state.car.length + 1 }
                this.setState({ car: [car, ...this.state.car] })
            })
            render() {
                return (
                    <div>
                        <button onClick={this.add}>添加</button>
                        <ul>
                            {this.state.car.map((carItem, carIndex) => {
                                return <li key={carIndex}>{carItem.name}---{carItem.num}</li>
                            })
                            }
                        </ul>


                    </div>
                )
            }
        }
        ReactDOM.render(<Demo />, document.getElementById('text'))
    </script>
  • 本来只需要操作一条数据,现在全部都需要重新挂真实DOM,数据一多性能就差

在这里插入图片描述

1.2.3使用index做索引值导致数据错乱
  • 1.input框写上内容2.点击添加时input内容没有改变
    虚拟dom没有value值,只有放在真实dom上才有
  <script type="text/babel">
        /**
        * index慢动作回放
        * 初始数据:
        * { name: '兰博基尼', num: 1000, id: 1 }
        * { name: '拖拉机', num: 2000, id: 2 }
        * 
        * 初始虚拟DOM:
        * <li key=0>兰博基尼---1000<input /></li>
        * <li key=1>拖拉机---2000<input /></li>
        * 
        * 更新后数据
        * { name: '玛莎拉蒂', num: 3000, id: 3 }
        * { name: '兰博基尼', num: 1000, id: 1 }
        * { name: '拖拉机', num: 2000, id: 2 }
        * 
        * 更新数据后的虚拟DOM
        * <li key=0>玛莎拉蒂---3000<input /></li>
        * <li key=1>兰博基尼---1000<input /></li>
        * <li key=2>拖拉机---2000<input /></li>
       */
        /**
         * id慢动作回放
         * 初始数据:
         * { name: '兰博基尼', num: 1000, id: 1 }
         * { name: '拖拉机', num: 2000, id: 2 }
         * 
         * 初始虚拟DOM:
         * <li key=1>兰博基尼---1000<input /></li>
         * <li key=2>拖拉机---2000<input /></li>
         * 
         * 更新后数据
         * { name: '玛莎拉蒂', num: 3000, id: 3 }
         * { name: '兰博基尼', num: 1000, id: 1 }
         * { name: '拖拉机', num: 2000, id: 2 }
         * 
         * 更新数据后的虚拟DOM
         * <li key=3>玛莎拉蒂---3000<input /></li>
         * <li key=1>兰博基尼---1000<input /></li>
         * <li key=2>拖拉机---2000<input /></li>
        */
        class Demo extends React.Component {
            state = { car: [{ name: '兰博基尼', num: 1000, id: 1 }, { name: '拖拉机', num: 2000, id: 2 }] }
            add = (() => {
                const car = { name: "玛莎拉蒂", num: 3000, id: this.state.car.length + 1 }
                this.setState({ car: [car, ...this.state.car] })
            })
            render() {
                return (
                    <div>
                        <button onClick={this.add}>添加</button>
                        <h1>使用index</h1>
                        <ul>
                            {this.state.car.map((carItem, index) => {
                                return <li key={index}>{carItem.name}---{carItem.num}<input /></li>
                            })
                            }
                        </ul>
                        <h1>使用id</h1>
                        <ul>
                            {this.state.car.map((carItem) => {
                                return <li key={carItem.id}>{carItem.name}---{carItem.num}<input /></li>
                            })
                            }
                        </ul>


                    </div>
                )
            }
        }
        ReactDOM.render(<Demo />, document.getElementById('text'))
    </script>

在这里插入图片描述

在这里插入图片描述

1.2.4使用唯一值做key
<script type="text/babel">
        /**
         * 慢动作回放
         * 初始数据:
         * { name: '兰博基尼', num: 1000, id: 1 }
         * { name: '拖拉机', num: 2000, id: 2 }
         * 
         * 初始虚拟DOM:
         * <li key=1>兰博基尼---1000</li>
         * <li key=2>拖拉机---2000</li>
         * 
         * 更新后数据
         * { name: '玛莎拉蒂', num: 3000, id: 3 }
         * { name: '兰博基尼', num: 1000, id: 1 }
         * { name: '拖拉机', num: 2000, id: 2 }
         * 
         * 更新数据后的虚拟DOM
         * <li key=3>玛莎拉蒂---3000</li>
         * <li key=1>兰博基尼---1000</li>
         * <li key=2>拖拉机---2000</li>
        */
        class Demo extends React.Component {
            state = { car: [{ name: '兰博基尼', num: 1000, id: 1 }, { name: '拖拉机', num: 2000, id: 2 }] }
            add = (() => {
                const car = { name: "玛莎拉蒂", num: 3000, id: this.state.car.length + 1 }
                this.setState({ car: [car, ...this.state.car] })
            })
            render() {
                return (
                    <div>
                        <button onClick={this.add}>添加</button>
                        <ul>
                            {this.state.car.map((carItem) => {
                                return <li key={carItem.id}>{carItem.name}---{carItem.num}</li>
                            })
                            }
                        </ul>


                    </div>
                )
            }
        }
        ReactDOM.render(<Demo />, document.getElementById('text'))
    </script>

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值