2. React面向组件编程

1. 基本理解和使用

先在Google安装React Develop Tools插件。

以美团页面为例,安装成功后可以在开发者工具看到添加了Components和Prifiler选项:
在这里插入图片描述


react中定义组件

  1. 函数式组件:适用于简单组件的定义

在这里插入图片描述
在这里插入图片描述

执行ReactDOM.render(<Demo/>, document.getElementById('test'))之后,发生了什么?

  1. React解析组件标签,找到Demo组件
  2. 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,呈现在页面中

  1. 类式组件:适用于复杂组件的定义

在这里插入图片描述

在这里插入图片描述

执行ReactDOM.render(<MyComponent />, document.getElementById('test'))之后,发生了什么?

  1. React解析组件标签,找到MyComponent组件
  2. 发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法
  3. 将render返回的虚拟DOM转为真实DOM,呈现在页面中

2. 组件三大核心属性之:state

state是组件对象最重要的属性,值是对象(可以包含多个 key-value 的组合)。

可以通过更新组件的state来更新对应的页面显示(重新渲染组件)。

注意:

  1. 组件中render方法中的this为组件实例对象
  2. 解决组件自定义的方法中this为undefined的问题:
    • 强制绑定this:通过函数对象的bind()
    • 箭头函数
  3. 状态数据, 不能直接修改或更新
<body>
    <div id="test"></div>

    <script src="../../js/react.development.js"></script>
    <script src="../../js/react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>


    <script type="text/babel">
        // 1. 创建类式组件
        class Weather extends React.Component {
            constructor(props) {
                super(props);
                // 初始化状态
                this.state = {
                    isHot: true
                }
                // 解决changeWeather中this的指向问题
                this.changeWeather = this.changeWeather.bind(this);
            }

            // changeWeather放在Weather的原型对象上,供实例调用
            // changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
            changeWeather() {
                // 类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
                console.log(this); // undefined

                // 获取原来的isHot值
                const isHot = this.state.isHot
                // 状态(state)不能直接更改,要借助内置API(setState)去更改
                // this.state.isHot = !isHot // 错误写法
                this.setState({
                    isHot: !isHot
                })
            }

            render() {
                // 读取状态
                const { isHot } = this.state;
                return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉快'}</h1>
            }
        }

        // 2. 渲染组件到页面
        ReactDOM.render(<Weather />, document.getElementById('test'));
    </script>
</body>

state的简写方式:

    <script type="text/babel">
        class Weather extends React.Component {
            state = {
                isHot: true
            }

            // 自定义方法,要用赋值语句的形式 + 箭头函数
            changeWeather = () => {
                const isHot = this.state.isHot
                this.setState({
                    isHot: !isHot
                })
            }

            render() {
                const { isHot } = this.state;
                return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉快'}</h1>
            }
        }

        ReactDOM.render(<Weather />, document.getElementById('test'));
    </script>

3. 组件三大核心之:props

每个组件都会有 props 属性,组件标签的所有属性都保存在 props 中。

3.1 props基础

props的简单使用:

    <script type="text/babel">
        // 创建组件
        class Person extends React.Component {
            render() {
                console.log(this);

                // 提前解构赋值,就可以直接使用解构之后的值
                const { name, age, gender } = this.props;
                
                return (
                    <ul>
                        <li>姓名:{this.props.name}</li>
                        <li>性别:{this.props.age}</li>
                        <li>年龄:{this.props.gender}</li>

                        <br />

                        <li>姓名:{name}</li>
                        <li>性别:{age}</li>
                        <li>年龄:{gender}</li>
                    </ul>
                )
            }
        }

        ReactDOM.render(<Person name="张三" age="12" gender="男" />, document.getElementById('test'));
    </script>

在这里插入图片描述


批量传递props:

    <script type="text/babel">
        // 创建组件
        class Person extends React.Component {
            render() {
                console.log(this);

                // 提前解构赋值,就可以直接使用解构之后的值
                const { name, age, gender } = this.props;

                return (
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性别:{age}</li>
                        <li>年龄:{gender}</li>
                    </ul>
                )
            }
        }

        // 实际开发中获取到的数据一般是一个对象
        const p = { name: "张三", age: "12", gender: "男" }
        // ReactDOM.render(<Person name="张三" age="12" gender="男" />, document.getElementById('test'));
        ReactDOM.render(<Person {...p} />, document.getElementById('test'));
    </script>

对props进行限制:

<body>
    <div id="test"></div>

    <script src="../../js/react.development.js"></script>
    <script src="../../js/react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>

    <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script src="../../js/prop-types.js"></script>


    <script type="text/babel">
        // 创建组件
        class Person extends React.Component {
            render() {
                console.log(this);

                // 提前解构赋值,就可以直接使用解构之后的值
                const { name, age, gender } = this.props;

                return (
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性别:{age + 1}</li>
                        <li>年龄:{gender}</li>
                    </ul>
                )
            }
        }

        // 对标签属性做类型、必要性的限制(注意p的大小写)
        Person.propTypes = {
            // name: PropTypes.string, // 限制name类型为字符串
            name: PropTypes.string.isRequired, // 设置name为字符串且必传
            gender: PropTypes.string,
            age: PropTypes.number,
            speak: PropTypes.func // 限制speak为函数
        }
        // 设置默认值
        Person.defaultProps = {
            gender: '保密',
            age: 18
        }

        function speak() {
            console.log("hello");
        }

        // 实际开发中获取到的数据一般是一个对象
        ReactDOM.render(<Person name="张三" age={12} speak={speak} />, document.getElementById('test'));
    </script>
</body>

props是只读的:

this.props.name = '李四'; // props是只读的,此行代码会报错

props的简写方式:

    <script type="text/babel">
        // 创建组件
        class Person extends React.Component {
            // 对标签属性做类型、必要性的限制(注意p的大小写)
            static propTypes = {
                name: PropTypes.string.isRequired, // 设置name为字符串且必传
                gender: PropTypes.string,
                age: PropTypes.number,
                speak: PropTypes.func // 限制speak为函数
            }
            
            // 设置默认值
            static defaultProps = {
                gender: '保密',
                age: 18
            }

            render() {
                console.log(this);

                // 提前解构赋值,就可以直接使用解构之后的值
                const { name, age, gender } = this.props;

                return (
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性别:{age + 1}</li>
                        <li>年龄:{gender}</li>
                    </ul>
                )
            }
        }

        function speak() {
            console.log("hello");
        }

        // 实际开发中获取到的数据一般是一个对象
        ReactDOM.render(<Person name="张三" age={12} speak={speak} />, document.getElementById('test'));
    </script>

3.2 类式组件中的构造器与props

// 构造器是否接收props,是否传递给super,取决于是否希望在构造器中通过this访问props
constructor(props) {
    super(props);
    console.log(this.props); // {name: '张三', gender: '保密', age: 18}
}

// constructor() {
//     super();
//     console.log(this.props); // undefined
// }

3.3 函数式组件使用props

<script type="text/babel">
    function Person(props) {
        const { name, age, gender } = props;
        return (
            <ul>
                <li>姓名:{name}</li>
                <li>性别:{age + 1}</li>
                <li>年龄:{gender}</li>
            </ul>
        )
    }
    ReactDOM.render(<Person name="张三" gender="男" age={18} />, document.getElementById('test'));
</script>

4. 组件三大核心之:ref

组件内的标签可以定义ref属性来标识自己。

4.1 ref基础

字符串形式的ref(不建议使用):

<script type="text/babel">
    // 创建组件
    class Demo extends React.Component {
        // 展示左侧输入框的数据
        showData = () => {
            const { input1 } = this.refs;
            alert(input1.value);
        }
        // 展示右侧输入框数据
        showData2 = () => {
            const { input2 } = this.refs;
            alert(input2.value);
        }
        render() {
            return (
                <div>
                    <input ref="input1" type="text" placeholder="点击按钮提示数据" />
                    <button onClick={this.showData}>点击提示左侧数据</button>
                    <input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据" />
                </div>
            )
        }
    }
    // 渲染组件到页面
    ReactDOM.render(<Demo />, document.getElementById('test'));
</script>

回调函数形式的ref:

<script type="text/babel">
    // 创建组件
    class Demo extends React.Component {
        // 展示左侧输入框的数据
        showData = () => {
            const { input1 } = this;
            alert(input1.value);
        }
        render() {
            return (
                <div>
                    <input ref={currentNode => this.input1 = currentNode} type="text" placeholder="点击按钮提示数据" />
                    <button onClick={this.showData}>点击提示左侧数据</button>
                </div>
            )
        }
    }
    // 渲染组件到页面
    ReactDOM.render(<Demo />, document.getElementById('test'));
</script>

ref 回调函数以内联函数的方式定义时,在更新过程中会被执行两次:

  • 第一次传入参数null(初始化)
  • 第二次传入参数DOM元素
<script type="text/babel">
    // 创建组件
    class Demo extends React.Component {
        state = {
            isHot: false
        }
        // 展示左侧输入框的数据
        showData = () => {
            const { input1 } = this;
            alert(input1.value);
        }
        // 改变天气
        changeWeather = () => {
            const { isHot } = this.state;
            this.setState({
                isHot: !isHot
            })
        }
        render() {
            const { isHot } = this.state;
            return (
                <div>
                    <h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2>
                    <input ref={currentNode => { this.input1 = currentNode, console.log(currentNode); }} type="text" placeholder="点击按钮提示数据" />
                    <button onClick={this.showData}>点击提示左侧数据</button>
                    <button onClick={this.changeWeather}>点击切换天气</button>
                </div>
            )
        }
    }
    // 渲染组件到页面
    ReactDOM.render(<Demo />, document.getElementById('test'));
</script>

点击切换天气后,执行结果如下:

在这里插入图片描述


将ref的回调函数定义成class的绑定函数的方式:

可以避免上述问题。

<script type="text/babel">
    // 创建组件
    class Demo extends React.Component {
        state = {
            isHot: false
        }
        // 展示左侧输入框的数据
        showData = () => {
            const { input1 } = this;
            alert(input1.value);
        }
        // 改变天气
        changeWeather = () => {
            const { isHot } = this.state;
            this.setState({
                isHot: !isHot
            })
        }
        saveInput = (currentNode) => {
            this.input1 = currentNode;
            console.log(currentNode);
        }
        render() {
            const { isHot } = this.state;
            return (
                <div>
                    <h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2>
                    {/*<input ref={currentNode => { this.input1 = currentNode, console.log(currentNode); }} type="text" placeholder="点击按钮提示数据" />*/}
                    <input ref={this.saveInput} type="text" placeholder="点击按钮提示数据" />
                    <button onClick={this.showData}>点击提示左侧数据</button>
                    <button onClick={this.changeWeather}>点击切换天气</button>
                </div>
            )
        }
    }
    // 渲染组件到页面
    ReactDOM.render(<Demo />, document.getElementById('test'));
</script>

此时不论怎么切换天气状态,因为saveInput已经放在自立自身,所以不会频繁去调用saveInput;就算重新调用render,也知道它已经被调用过,不是一个新的函数。


4.2 createRef的使用

<script type="text/babel">
    // 创建组件
    class Demo extends React.Component {
        /**
         * React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点
         * 如果button也使用了myRef,那么后一个会覆盖前一个,输出的结果是button的
         * 所以用几个就得创建几个
         */
        myRef = React.createRef();
        // 展示左侧输入框的数据
        showData = () => {
            alert(this.myRef.current.value);
        }
        render() {
            return (
                <div>
                    {/*此时会把ref所在的节点(input)直接存储到myRef容器中*/}
                    <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
                    <button onClick={this.showData}>点击提示左侧数据</button>
                </div>
            )
        }
    }
    // 渲染组件到页面
    ReactDOM.render(<Demo />, document.getElementById('test'));
</script>

5. react中的事件处理

  1. 通过onXxx属性指定事件处理函数
    • React为了更好的兼容性,使用的是自定义(合成)事件,而非原生的DOM事件
    • React中的事件是通过事件委托方式处理的(委托给组件最外层元素),能更高效
  2. 通过event.target得到发生事件的DOM元素对象,能避免过度使用ref
<script type="text/babel">
    // 创建组件
    class Demo extends React.Component {
    // 发生事件的元素正好是要操作的元素时,通过event.target也能实现,不用ref
        showData = (event) => {
            alert(event.target.value);
        }
        render() {
            return (
                <div>
                    <input onBlur={this.showData} type="text" placeholder="失去焦点提示数据" />
                </div>
            )
        }
    }
    // 渲染组件到页面
    ReactDOM.render(<Demo />, document.getElementById('test'));
</script>

6. 收集表单数据

6.1 受控组件

<script type="text/babel">
    // 创建组件
    class Login extends React.Component {
        state = {
            username: '',
            password: ''
        }

        saveUsername = (event) => {
            this.setState({
                username: event.target.value
            })
        }

        savePassword = (event) => {
            this.setState({
                password: event.target.value
            })
        }

        handleSubmit = (event) => {
            event.preventDefault() // 阻止表单默认提交
            const { username, password } = this.state
            alert(`用户名是:${username}, 密码是:${password}`)
        }
        
        render() {
            return (
                <form onSubmit={this.handleSubmit}>
                    用户名:<input onChange={this.saveUsername} type="text" name="username" />
                    密  码:<input onChange={this.savePassword} type="password" name="password" />
                    <button>登录</button>
                </form>
            )
        }
    }
    // 渲染组件到页面
    ReactDOM.render(<Login />, document.getElementById('test'));
</script>

代码优化:

onChange需要一个函数作为回调

  1. 用柯里化函数实现
<script type="text/babel">
    // 创建组件
    class Login extends React.Component {
        state = {
            username: '',
            password: ''
        }
        saveFormData = (dataType) => {
            return (event) => {
                this.setState({
                    [dataType]: event.target.value
                })
            }
        }
        handleSubmit = (event) => {
            event.preventDefault() // 阻止表单默认提交
            const { username, password } = this.state
            alert(`用户名是:${username}, 密码是:${password}`)
        }
        render() {
            return (
                <form onSubmit={this.handleSubmit}>
                    用户名:<input onChange={this.saveFormData('username')} type="text" name="username" />
                    密  码:<input onChange={this.saveFormData('password')} type="password" name="password" />
                    <button>登录</button>
                </form>
            )
        }
    }
    // 渲染组件到页面
    ReactDOM.render(<Login />, document.getElementById('test'));
</script>
  1. 不用柯里化函数实现:
<script type="text/babel">
    // 创建组件
    class Login extends React.Component {
        state = {
            username: '',
            password: ''
        }
        saveFormData = (dataType, event) => {
            this.setState({
                [dataType]: event.target.value
            })
        }
        handleSubmit = (event) => {
            event.preventDefault() // 阻止表单默认提交
            const { username, password } = this.state
            alert(`用户名是:${username}, 密码是:${password}`)
        }
        render() {
            return (
                <form onSubmit={this.handleSubmit}>
                    用户名:<input onChange={(event) => {this.saveFormData('username', event.target.value)}} type="text" name="username" />
                    密  码:<input onChange={(event) => {this.saveFormData('password', event.target.value)}} type="password" name="password" />
                    <button>登录</button>
                </form>
            )
        }
    }
    // 渲染组件到页面
    ReactDOM.render(<Login />, document.getElementById('test'));
</script>

6.2 非受控组件

现用现取页面中所有输入类DOM时,就是非受控组件。

<script type="text/babel">
    // 创建组件
    class Login extends React.Component {
        handleSubmit = (event) => {
            event.preventDefault() // 阻止表单默认提交
            const {username, password} = this
            alert(`用户名是:${username.value}, 密码是:${password.value}`)
        }
        render() {
            return (
                <form onSubmit={this.handleSubmit}>
                    用户名:<input ref={c => this.username = c} type="text" name="username" />
                    密  码:<input ref={c => this.password = c} type="password" name="password" />
                    <button>登录</button>
                </form>
            )
        }
    }
    // 渲染组件到页面
    ReactDOM.render(<Login />, document.getElementById('test'));
</script>

在这里插入图片描述


7. 组件的生命周期

7.1 生命周期的三个阶段(旧)

在这里插入图片描述

  1. 初始化阶段:ReactDOM.render() 触发 – 初次渲染
    • constructor()
    • componentWillMount()
    • render()
    • componentDidMount()
  2. 更新阶段: 由组件内部 this.setState() 或父组件重新 render 触发
    1. shouldComponentUpdate()
    2. componentWillUpdate()
    3. render()
    4. componentDidUpdate
  3. 卸载组件:ReactDOM.unmountComponentAtNode() 触发
    1. componentWillUnmount()

常用组件:

  1. componentDidMount:一般在这个钩子中做一些初始化的事,如开启定时器、发送网络请求、订阅消息等
  2. componentWillunmount:一般在这个钩子中做一些收尾的事,如关闭定时器、取消订阅消息
  3. render:必须使用

<script type="text/babel">
    // 创建组件
    class Count extends React.Component {
        // 构造器
        constructor(props) {
            console.log('count-constructor');
            super(props)
            // 初始化状态
            this.state = {
                count: 0
            }
        }
        // +1 按钮的回调
        add = () => {
            const { count } = this.state
            this.setState({
                count: count + 1
            })
        }
        // 卸载组件按钮的回调
        death = () => {
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }
        // 强制更新按钮的回调
        force = () => {
            this.forceUpdate()
        }
        // 组件将要挂载的钩子
        componentWillMount() {
            console.log('count-conponentWillMount');
        }
        // 组件挂载完毕的钩子
        componentDidMount() {
            console.log('count-componentDidMount');
        }
        // 组件将要卸载的钩子
        componentWillUnmount() {
            console.log('count-componentWillUnmount');
        }
        /* 控制组件更新的阀门
         *  如果不写这个钩子,则默认返回true
         *  如果为返回值为false,则后续钩子不执行
        */
        shouldComponentUpdate() {
            console.log('count-shouldComponentUpdate');
            return true;
        }
        // 组件将要更新的钩子
        componentWillUpdate() {
            console.log('count-componentWillUpdate');
        }
        // 组件更新完毕的钩子
        componentDidUpdate() {
            console.log('count-componentDidUpdate');
        }
        render() {
            console.log('count-render');
            return (
                <div>
                    <h2>当前求和为:{this.state.count}</h2>
                    <button onClick={this.add}>点击+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>强制更新</button>
                </div>
            )
        }
    }
    
    // 渲染组件
    ReactDOM.render(<Count />, document.getElementById('test'));
</script>
</script>

在这里插入图片描述

1. 组件挂载流程

在这里插入图片描述

2. setState流程

点击按钮+1时,setState() -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate 路线(正常更新):

在这里插入图片描述

3. forceUpdate流程

点击强制更新按钮时,forceUpdate() -> componentWillUpdate -> render -> componentDidUpdate 路线(强制更新,当不想对状态做出任何修改但想更新时可以使用):

在这里插入图片描述

4. 卸载组件

点击卸载组件时:

在这里插入图片描述

5. 父组件render流程

父组件render -> componentWillReceiveProps -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate 路线:

<script type="text/babel">
    // 创建组件
    class Father extends React.Component {
        // 初始化状态
        state = {
            car: '奥迪'
        }
        change = () => {
            this.setState({
                car: '法拉利'
            })
        }
        render() {
            return (
                <div>
                    <div>Father</div>
                    <button onClick={this.change}>换车</button>
                    <Child car={this.state.car} />
                </div>
            )
        }
    }
    class Child extends React.Component {
        /**
         * 组件将要接受新的props的钩子
         *  调用时机:点击按钮之后才调用
         *  能接受参数
         */
        componentWillReceiveProps(props) {
            console.log('child-componentWillReceiveProps', props);
        }
        // 控制组件更新的阀门
        shouldComponentUpdate() {
            console.log('child-shouldComponentUpdate');
            return true;
        }
        // 组件将要更新的钩子
        componentWillUpdate() {
            console.log('child-componentWillUpdate');
        }
        // 组件更新完毕的钩子
        componentDidUpdate() {
            console.log('child-componentDidUpdate');
        }
        render() {
            console.log('count-render');
            return (
                <div>Child组件接收到的车是:{this.props.car}</div>
            )
        }
    }
    // 渲染组件
    ReactDOM.render(<Father />, document.getElementById('test'));
</script>

在这里插入图片描述


7.2 对比新(17)旧版本生命周期

如果在新版本中使用旧版本的钩子,会发出弃用警告:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


7.3 新版本生命周期

在这里插入图片描述

1. getDerivedStateFromProps

该方法适用于罕见的用例,即state大的值任何时候都取决于props。

需要定义它作为一个静态方法,而不应该将它给实例使用。

static getDerivedStateFromProps() {
    console.log('conut-getDerivedStateFromProps');
    // return null;
    return { count: 100 };
}

返回null时:

在这里插入图片描述

在这里插入图片描述
返回一个状态对象:

在这里插入图片描述
在这里插入图片描述

但此时点击+1按钮没有反应。

能接受props参数:

static getDerivedStateFromProps(props) {
    console.log('conut-getDerivedStateFromProps', props);
    // return null;
    return { count: 100 };
}

在这里插入图片描述
传递props之后:

ReactDOM.render(<Count count={199}/>, document.getElementById('test'));
static getDerivedStateFromProps(props) {
    console.log('conut-getDerivedStateFromProps', props);
    // return null;
    return props;
}

在这里插入图片描述
在这里插入图片描述
加上state:

static getDerivedStateFromProps(props, state) {
    console.log('conut-getDerivedStateFromProps', props, state);
    // return null;
    return props;
}

在这里插入图片描述

这个方法不推荐使用,派生状态会导致代码冗余,并且组件难以维护。


2. getSnapshotBeforeUpdate

通过这个方法可以在页面马上更新之前获取前面的信息。

getSnapshotBeforeUpdate() {
    console.log('count-getSnapshotBeforeUpdate');
    // return null;
    return 'aaa';
}
// 组件更新完毕的钩子
componentDidUpdate(preProps, preState, snapshotValue) {
    console.log('count-componentDidUpdate', preProps, preState, snapshotValue);
}

点击+1按钮之后:
在这里插入图片描述


8. key的作用

react/vue中key的作用?为什么遍历列表时,key最好不用index?

  1. 虚拟DOM中key的作用:
    1. 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。
    2. 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:
  1. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
    • 若虚拟DOM中内容没变, 直接使用之前的真实DOM
    • 若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
  2. 旧虚拟DOM中未找到与新虚拟DOM相同的key
    • 根据数据创建新的真实DOM,随后渲染到到页面
  1. 用index作为key可能会引发的问题:

    1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作。会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
    2. 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。
    3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作。仅用于渲染列表用于展示,使用index作为key是没有问题的。
  2. 开发中如何选择key?:

    1. 最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
    2. 如果确定只是简单的展示数据,用index也是可以的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值