美文网首页React系列
第七节:React列表渲染与数据收集

第七节:React列表渲染与数据收集

作者: 曹老师 | 来源:发表于2022-06-26 20:29 被阅读0次

1. 列表渲染

1.1 列表渲染说明:
  1. 列表渲染 先将列表数据转为React元素列表, 然后在渲染
  2. React会将React元素列表自动展开渲染
1.2 React元素列表渲染

说明:

  1. React元素列表是一个数组
  2. 只不过数组的每一项都是JSX语法的React元素

示例代码:

// 不使用到组件状态,因此定义函数组件测试
function MyCom(){
    // 1\. react元素列表,数组的每一项都是JSX语法的React元素
    // 将react元素列表保存在变量中
    let oList = [
        <li>苹果</li>,
        <li>香蕉</li>,
        <li>梨子</li>
    ]

    // 2.在react元素中使用{}语法将列表渲染
    // react会自动遍历列表,并将列表中的react元素进行渲染
    return <ul> { oList } </ul>
}

// 将组件渲染到页面上
ReactDOM.render(<MyCom /> ,document.getElementById("root"))

1.3 渲染列表数据

说明:

  1. React会将react元素列表遍历渲染
  2. 因此如果要渲染列表数据,就可以先将列表数据转为react元素列表
  3. 遍历列表的方式有很多中,普通for循环, for-in, for-of,forEach,map,reduce都可以使用
1.3.1 使用普通for循环遍历列表数据

示例代码:

function MyCom(){
    // 1\. 列表数据
    let listdata = ["苹果","香蕉","梨子"]

    // 2\. 普通for循环
    let oList = [];
    for(let i = 0; i< listdata.length ;i++){
        // 循环列表数据,将每一个数据包裹一层react元素,
        // 在push到新的oList数组中,oList就是react元素列表
        oList.push(<li>{listdata[i]}</li>)
    }
    return <ul> { oList } </ul>
}

1.3.2 使用for-in遍历列表数据

示例代码:

function MyCom(){

    // 1\. 列表数据
    let listdata = ["苹果","香蕉","梨子"]

    // 2\. for-in循环
    let oList = [];

    for(let index in listdata){
        // index 为listdata列表的索引
        // 通过索引取出数据包裹react元素,组成react元素列表
        oList.push(<li>{listdata[index]}</li>)
    }

    return <ul> { oList } </ul>
}

// 将组件渲染到页面上
ReactDOM.render(<MyCom /> ,document.getElementById("root"))

1.3.3 使用for-of遍历列表数据

示例代码:

function MyCom(){

    // 1\. 列表数据
    let listdata = ["苹果","香蕉","梨子"]

    // 2\. for-of循环
    let oList = [];

    for(let value of listdata){
        // for-of 直接取出数据,处理为react元素.列表
        oList.push(<li>{value}</li>)
    }

    return <ul> { oList } </ul>
}

// 将组件渲染到页面上
ReactDOM.render(<MyCom /> ,document.getElementById("root"))

1.3.4 使用forEach遍历列表数据

示例代码如下:

function MyCom(){

    // 1\. 列表数据
    let listdata = ["苹果","香蕉","梨子"]

    // 2\. forEach循环
    let oList = [];

    // forEach循环将列表数据转为react元素列表
    listdata.forEach(value => {
        oList.push(<li>{value}</li>)
    })

    return <ul> { oList } </ul>

}

// 将组件渲染到页面上
ReactDOM.render(<MyCom /> ,document.getElementById("root"))

1.3.5 使用map遍历列表数据

map会自动返回列表,因此不用使用push方法

示例代码如下:

function MyCom(){

    // 1\. 列表数据
    let listdata = ["苹果","香蕉","梨子"]

    // 2\. map循环
    // map 返回的就是回调函数return内容组成的数组
    let oList = listdata.map(value => {
        return <li>{ value }</li>
    })

    return <ul> { oList } </ul>

}

// 将组件渲染到页面上
ReactDOM.render(<MyCom /> ,document.getElementById("root"))

1.3.6 使用reduce遍历列表数据

示例代码:

function MyCom(){

    // 1\. 列表数据
    let listdata = ["苹果","香蕉","梨子"]

    // 2\. reduce循环
    let oList = listdata.reduce((prev,value) => {
        // 没事将数据包裹react元素后在push到数组中
        prev.push(<li>{ value }</li>)

        // 返回数组
        return prev
    },[])

    return  <ul> { oList } </ul>

}

// 将组件渲染到页面上
ReactDOM.render(<MyCom /> ,document.getElementById("root"))

比较常用的方法是: map和reduce两种方法来渲染列表数据

2. 列表渲染的key属性

2.1 可以属性的认识
  1. 在列表渲染中使用key来标记每一项,让React能识别每一个元素,

  2. 这样如果遇到添加或删除,会很有帮助,key属性要这个元素成为唯一

  3. key属性的值最好是这个元素列表中独一无二的字符串,通常我们用id来 作为元素的key

  4. 当元素没有id时,万不得已的情况下 可以使用index索引来作为key,通常不建议,因为这会导致性能的下降

  5. 如果你不指定可以,React将默认用索引index作为key,并在控制台提醒添加key属性

注意:

  1. key只在兄弟节点之间必须唯一
  2. key属性值会传递给React,不会传递给组件,如果需要 传递给组件,请使用其他属性传递
2.2 使用key属性渲染列表数据

// 1\. 列表数据
let names = ["HTML,CSS","JavaScript","Node","Vue","React"]

// 2\. 创建虚拟DOM
const ul = (
    <ul>
        { names.map( (item,index) => <li key={index}>{item}</li>) }
    </ul>
)

// 3\. 渲染虚拟DOM
ReactDOM.render(ul, document.getElementById('list'))

3. 受控组件与非受控组件

3.1 受控组件与非受控制组件说明
  1. 受控组件是指可以被rect状态控制的组件
  2. 非受控组件是可以任意输入内容,不受组件状态的控制,默认是就是非受控组件
3.2 非受控组件

说明:

  1. 非受控组件不受react状态影响
  2. 如果需要获取非受控组件的数据,使用ref属性

示例代码:

class MyCom extends React.Component{
    // 组件状态
    state = {
        username:"",
        password:""
    }

handleClick = () =>{
    // console.log(this);

    // 获取数据
    let username = this.userInput.value.trim();
    let password = this.passwordInput.value.trim();

    // 判断输入是否为空
    if(!username || !password){
        console.log("用户名或者密码不能为空")
        return;
    }

    // console.log(username,":",password)

    // 将数据添加到状态中
    this.setState(() => ({
        username,password
    }), () => {
        console.log("数据已经添加到状态中");
    })

}

render(){
    return (
        <div>
            <h2>非受控组件获取数据</h2>
            <p>
                用户名: 
                <input 
                    type="text"  
                    ref={input => this.userInput = input}
                    />
            </p>
            <p>
                密  码: 
                <input type="password" 
                    ref={input => this.passwordInput = input}
                    />
            </p>
            <button onClick={ this.handleClick }>点击</button>
        </div>
    )
}
}

// 将组件渲染到页面上
ReactDOM.render(<MyCom /> ,document.getElementById("root"))

3.3 受控组件

说明:

  1. 受控组件是指将表单绑定到状态上,
  2. 状态的值一但发生变化,输入空的内容也会发生变化,
  3. 状态的值不变,输入框不能输入任何内容
  4. 也就是说输入框中的内容被状态所控制

示例代码如下:

class MyCom extends React.Component{
    // 组件状态
    state = {
        username:"",
        password:""
    }

userChangeHandle = (event) =>{

    // // 获取用户名数据
    let username = event.target.value.trim();

    // 判断输入是否为空
    if(!username){
        console.log("用户名不能为空")
        return;
    }

    // console.log(username,":",password)

    // 将数据添加到状态中
    this.setState(() => ({
        username
    }), () => {
        console.log("用户名数据已经添加到状态中");
    })

}

pwChangeHandle = (event) =>{
    // console.log(this);
    // // 获取密码数据
    let password = event.target.value.trim();

    // 判断输入是否为空
    if(!password){
        console.log("密码不能为空")
        return;
    }

    // console.log(username,":",password)

    // 将数据添加到状态中
    this.setState(() => ({
        password
    }), () => {
        console.log("密码数据已经添加到状态中");
    })

}

render(){
    // 1\. 获取状态中的数据
    let {username, password} = this.state

    // 2\. 将状态中的数据绑定到输入框,此时输入框就是受控组件
    return (
        <div>
            <h2>非受控组件获取数据</h2>
            <p>
                用户名: 
                <input 
                    type="text" 
                    value={username}
                    onChange = { this.userChangeHandle }
                    />
            </p>
            <p>
                密  码: 
                <input type="password" 
                    value={password}
                    onChange = { this.pwChangeHandle }
                    />
            </p>
            <button onClick={ this.handleClick }>点击</button>
        </div>
    )
}
}

// 将组件渲染到页面上
ReactDOM.render(<MyCom /> ,document.getElementById("root"))

  1. 示例中标签输入内容没有任何限制,不被状态控制,
  2. 在通过ref

示例说明:

  1. 输入框的value值绑定到了状态中的数据,因此输入框就被状态控制
  2. 此时输入框不能输入任何内容, 因为是状态单向影响输入框,而且此时还会报错
  3. 如果我们希望能在输入框输入的内容,就需要绑定onChange事件
  4. 当输入内容时,通过onChange绑定的事件函数获取输入的内容,修改状态值
  5. 状态值一但发生变化,表单就会显示最新的数据. 看起来好像可以输入了

4. 收集表单数据

4.1 收集标签数据说明:
  1. 受控制和非受控组件都可以收集表单数据

  2. 但是非受控组件是在操作DOM,

  3. 受控组件不是在操作DOM, 按照react思想减少DOM操控,所以官网推荐受控组件

4.2 收集标签数据代码

使用受控组件收集标签数据

需求

  1. 收集用户输入的用户名,密码
  2. 收集性别爱好,单选复选数据
  3. 收集select数据

示例代码如下

class MyCom extends React.Component{
    // 组件状态
    state = {
        username:"",
        password:"",
        sex:"0",  // 0为男,1为女
        likes:[],
        province:""
    }

// 处理用户名
userChangeHandle = (event) =>{

    // // 获取用户名数据
    let username = event.target.value.trim();

    // 判断输入是否为空
    if(!username){
        console.log("用户名不能为空")
        return;
    }

    // console.log(username,":",password)

    // 将数据添加到状态中
    this.setState(() => ({
        username
    }))

}

// 处理密码
pwChangeHandle = (event) =>{
    // console.log(this);
    // // 获取密码数据
    let password = event.target.value.trim();

    // 判断输入是否为空
    if(!password){
        console.log("密码不能为空")
        return;
    }

    // console.log(username,":",password)

    // 将数据添加到状态中
    this.setState(() => ({
        password
    }))
}

// 处理性别 单选
changeSex = (event) => {
    let sex = event.target.value;

    this.setState(() => ({
        sex
    }))

}

// 处理爱好  多选
changeLike = (event) => {
    // 获取复选框改变的数据
    let like = event.target.value;

    // 获取状态中收集爱好的数据
    let {likes} = this.state

    // 判断状态中是否存在,存在就删除,不存在就添加
    if(!likes.includes(like)){
        likes.push(like)
    }else{
        likes = likes.filter(value => {
            return like != value
        })
    }

    // 更新数据
    this.setState(() => ({
        likes
    }))
}

// 获取省份数据
changeProvince = (event) => {
    let province = event.target.value;
    this.setState(() => ({
        province
    }))
}

render(){
    // 1\. 获取状态中的数据
    let {
        username, 
        password,
        sex,
        likes,
        province
    } = this.state

    // 2\. 将状态中的数据绑定到输入框,此时输入框就是受控组件
    return (
        <div>
            <h2>非受控组件获取数据</h2>
            <p>
                用户名: 
                <input 
                    type="text" 
                    value={username}
                    onChange = { this.userChangeHandle }
                    />
            </p>
            <p>
                密  码: 
                <input type="password" 
                    value={password}
                    onChange = { this.pwChangeHandle }
                    />
            </p>
            <p>
                性别: 
                <label htmlFor="male">
                    <input 
                        id="male"
                        type="radio" 
                        value="0"
                        checked={sex == 0 }
                        onChange = { this.changeSex }
                        />
                    男
                </label>
                <label htmlFor="female">
                    <input 
                        id="female"
                        type="radio" 
                        value="1"
                        checked={sex == 1 }
                        onChange = { this.changeSex }
                        />
                    女
                </label>
            </p>
            <p>
                爱好: 
                <label htmlFor="like1">
                    <input 
                        id="like1"
                        type="checkbox" 
                        value="游泳"
                        checked={ likes.some(like => like == "游泳") }
                        onChange = { this.changeLike }
                        />
                    游泳
                </label>
                <label htmlFor="like2">
                    <input 
                        id="like2"
                        type="checkbox" 
                        value="篮球"
                        checked={ likes.some(like => like == "篮球") }
                        onChange = { this.changeLike }
                        />
                    篮球
                </label>
                <label htmlFor="like3">
                    <input 
                        id="like3"
                        type="checkbox" 
                        value="足球"
                        checked={ likes.some(like => like == "足球") }
                        onChange = { this.changeLike }
                        />
                    足球
                </label>
            </p>
            <p>
                省份: 
                <select 
                    value={province} 
                    onChange={this.changeProvince }
                    >
                    <option value="">请选择</option>
                    <option value="北京">北京</option>
                    <option value="上海">上海</option>
                    <option value="广东">广东</option>
                    <option value="安徽">安徽</option>
                    <option value="湖南">湖南</option>
                </select>
            </p>
            <button onClick={ this.handleClick }>点击</button>
        </div>
    )
}
}

// 将组件渲染到页面上
ReactDOM.render(<MyCom /> ,document.getElementById("root"))

示例说明:

  1. 用户名,密码表单受控组件直接绑定value值
  2. 单选复选通过checked判断是否选择中,因此将状态中用来数据对应数据字段的数据跟value对比
  3. select受控组件收集数据,将value绑定在select标签上

5. 虚拟DOM与DOM Diff算法

image

初始化显示界面

  1. 创建虚拟DOM树(一般JS对象)
  2. 真实DOM树
  3. 将虚拟DOM添加真实DOM绘制界面显示

初始化看不出虚拟DOM的优势,优势主要体现在更新,因为页面大部分情况下都是在更新

更新界面

  1. setState() 更新状态
  2. 重新创建虚拟DOM树
  3. 新/旧树比较差异
  4. 更新差异对应的真实DOM
  5. 局部界面重绘

为什么状态不能直接就改,而是要通过setState,因为直接修改没法比较,setState会重新创建新状态,生成新的虚拟DOM,可以与原来状态和虚拟DOM进行对比

例子演示;


// 1\. 定义组件
class Hello extends React.Component {

    constructor (){
        super()

        // 定义状态
        this.state = {
            date: new Date()
        }

    }

    componentWillMount(){
        setInterval(()=>{
            this.setState({
                date: new Date()
            })
        },1000)
    }

    render(){
        console.log('render()')
        let {date} = this.state;

        return (
            <div>
                输入内容: <input type="text" /> <span>{date.toTimeString()}</span>
            </div> 
        )
    }
}

// 2\. 渲染组件标签
ReactDOM.render(
    <Hello />, 
    document.getElementById('box')
)

相关文章

  • 第七节:React列表渲染与数据收集

    1. 列表渲染 1.1 列表渲染说明: 列表渲染 先将列表数据转为React元素列表, 然后在渲染 React会将...

  • 第七节:React列表渲染与数据收集

    1. 列表渲染 1.1 列表渲染说明: 列表渲染 先将列表数据转为React元素列表, 然后在渲染 React会将...

  • 浅谈 React 列表渲染

    ? React 的列表渲染 key 与 Reconciliation List and Keys - ReactR...

  • React 列表与表单

    列表 在React中,拿到一组数据后,一般会用map方法来遍历渲染。 表单 HTML 表单元素与 React 中的...

  • React性能优化指南

    1、在专用组件中渲染列表 这点在渲染大型数据集合的时候尤为重要。React在渲染大型数据集合时表现的非常差,因为协...

  • 关于key

    每当一个列表重新渲染时,React 会根据每一项列表元素的 key 来检索上一次渲染时与每个 key 所匹配的列表...

  • React.js 小书 Lesson13 - 渲染列表数据

    React.js 小书 Lesson13 - 渲染列表数据 本文作者:胡子大哈本文原文:http://huzike...

  • 4.React中Memo实现指定组件进行渲染

    memo可以解决react渲染时的效率问题,react可以将数据渲染在视图中,如果数据没有变化,视图还是重新渲染。...

  • 列表渲染与条件渲染

    作者 | Jeskson来源 | 达达前端小酒馆 列表渲染与条件渲染 如何渲染数组类型和对象类型的数据 渲染数...

  • React项目实战四

    选择城市列表 选择城市列表渲染后的界面: 1,获取并处理城市列表数据 接口返回的数据结构: 渲染城市列表的数据格式...

网友评论

    本文标题:第七节:React列表渲染与数据收集

    本文链接:https://www.haomeiwen.com/subject/kltgvrtx.html