六、React(Component)


前言

本文介绍react的重中之重,react的组件。组件是react的核心所在,第一部分先介绍组件的基础内容,并且做一个组件能实行盒子左右移动的组件box帮助理解组件内容。
第二部分介绍组件与组件之间的关系以及组件数据与函数的之间的相互调用。


一、component基础

1.安装bootstrap库:

npm i bootstrap
bootstrap的引入方式:
import 'bootstrap/dist/css/bootstrap.css';


2.创建Component
创建按钮
当子节点数量大于1时,可以用<div><React.Fragment>将其括起来。

import React, { Component } from 'react';

class Box extends Component
	state = { 
	        x : 0,
	        colors : [],
	};
	render() { 
	   return (
	   <React.Fragment>
	                <div></div>
	                <button>left</button>
	                 <button>right</button>
		</React.Fragment>
		);
	}
}

3.内嵌表达式
JSX中使用{}嵌入表达式。

 render() { 
        return (
            <React.Fragment>
                <div>{this.state.x}</div>
                <button>left</button>
                <button>right</button>
            </React.Fragment>
        );
    }

4.设置属性
class -> className
CSS属性:background-color -> backgroundColor,其它属性类似

 render() { 
        return (
            <React.Fragment>
                <div>{this.state.x}</div>
                <button className='btn btn-primary m-2'>left</button>
                <button className='btn btn-success m-2' >right</button>
            </React.Fragment>
        );
    }

5.数据驱动改变Style
通过修改this.state.x的值,给样式修改不同的style

render() { 
       return (
           <React.Fragment>
               <div style={this.getStyle()} >{this.state.x}</div>
               <button className='btn btn-primary m-2'>left</button>
               <button className='btn btn-success m-2' >right</button>
           </React.Fragment>
       );
   }
   
getStyle(){
       let styles = {
           width : "100px",
           height: "50px",
           color : "white",
           lineHeight:"50px",
           borderRadius:5,
           textAlign: "center",
           backgroundColor : "lightblue",  //注意都要换成驼峰命名法
           marginLeft:this.state.x * 10,
       };

       if(this.state.x % 2 === 0) {
           styles.backgroundColor = 'orange';
       }

       return styles;
   }

6.渲染列表
使用map函数
每个元素需要具有唯一的key属性,用来帮助React快速找到被修改的DOM元素。

 state = { 
        x : 0,
        colors : ['red','green','blue'],
    };
    
 render() { 
        return (
            <React.Fragment>
                <div style={this.getStyle()} >{this.state.x}</div>
                <button className='btn btn-primary m-2'>left</button>
                <button className='btn btn-success m-2' >right</button>
                {this.state.colors.map(color => (
                    <div key={color}>{color}</div>  //key属性用来帮助React快速找到被修改的DOM元素。
                ))}
            </React.Fragment>
        );
    }

7.Conditional Rendering
利用逻辑表达式的短路原则。

与表达式中 expr1 && expr2,当expr1为假时返回expr1的值,否则返回expr2的值
或表达式中 expr1 || expr2,当expr1为真时返回expr1的值,否则返回expr2的值

 state = { 
        x : 0,
        colors : [],
    };
{this.state.colors.length === 0 && <p>No colors</p>}

8.绑定事件
注意妥善处理好绑定事件函数的this

    handleClickLeft = (step) => {
        console.log(step); 
     	 console.log("click left",this);
    }
    handleClickRight = () => {
        console.log("click right",this);
    }

    render() { 
        return (
            <React.Fragment>
                <div style={this.getStyle()}>{this.state.x}</div>
                <button onClick={() => this.handleClickLeft(10)} className='btn btn-primary m-2'>left</button> // 添加了两个事件函数,第一个写法可以传入参数
                <button onClick={this.handleClickRight} className='btn btn-success m-2'>right</button> //无法传入参数
            </React.Fragment>
        );
    }

9.修改state
需要使用this.setState()函数
每次调用this.setState()函数后,会重新调用this.render()函数,用来修改虚拟DOM树。React只会修改不同步的实际DOM树节点。

    handleClickLeft = (step) => {
        this.setState({        //如果想要我们的修改改变render函数,需要调用一下setState
            x : this.state.x - 1,
        })
    }
    handleClickRight = () => {
        this.setState({
            x : this.state.x + 1,
        })
    }
 render() { 
        return (
            <React.Fragment>
                <div style={this.getStyle()}>{this.state.x}</div>
                <button onClick={() => this.handleClickLeft(10)} className='btn btn-primary m-2'>left</button> // 添加了两个事件函数,第一个写法可以传入参数
                <button onClick={this.handleClickRight} className='btn btn-success m-2'>right</button> //无法传入参数
            </React.Fragment>
        );
    }

10.其它:
数组中用filter删除元素方法。
filter会帮我们遍历数组内的每一个值,如果返回值会false则保留,true则删除元素


    state = {  
        solutions : [
            {key : 0,number : 1164,title :"背包问题",views:2930},
            {key : 1,number : 1165,title :"背包问题",views:2930},
            {key : 2,number : 1166,title :"背包问题",views:2930},
            {key : 3,number : 1166,title :"背包问题",views:2930},
            {key : 4,number : 1167,title :"背包问题",views:2930},
            {key : 5,number : 1168,title :"背包问题",views:2930},
            {key : 6,number : 1169,title :"背包问题",views:2930},
            {key : 7,number : 1113,title :"背包问题",views:2930},
        
        ],  
    } 
    
    handleClickdelete = (s) => {
        const solutions = this.state.solutions.filter(solution => solution !== s);   //filter会帮我们遍历数组内的每一个值,如果返回值会false则保留,true则删除元素
        this.setState({
            solutions : solutions,
        }) ;
    }
    render{
    	...
    	<button onClick={() => this.handleClickdelete(solution)} className='btn btn-danger'>删除</button>
    }

二、Component的组合运用

首先创建APP,Boxes,Navber组件,APP组件中包含着 Boxes组件和Navber组件,并且让Boxes组件中包含一系列Box组件。

1. 从上往下传递数据
通过this.props属性可以从上到下传递数据。
此时Boxes为App的子结点,父节点传给子节点即可用props属性。

App在Boxes标签中插入要传入的元素即可,可以传递变量,数据,函数,对象,类无论啥都可以传递。

App类组件中的render函数

render() { 
        return (
            <React.Fragment>
                <NavBar  boxesCount={this.state.boxes.length}/>
                <Boxes 
                    boxes={this.state.boxes}
                    onReset={this.handleReset}
                    onLeft={this.handleClickLeft}
                    onRight={this.handleClickRight}
                    onDelete={this.handleDelete}
                />

            </React.Fragment>
        );
    }

Boxes里调用父组件的就是用props属性。
例子:

class Boxes extends Component {
    render() { 
        return (
            <React.Fragment>    
                <button onClick={this.props.onReset} style={{marginBottom: "15px"}} className='btn btn-info'>Reset</button>
                {this.props.boxes.map(box => (
                    <Box key={box.id}   //Boxes组件传给Box组件
                        id = {box.id}
                        x = {box.x}
                        box = {box}
                        name = "lyy"
                        onDelete={this.props.onDelete}
                        onLeft={() => this.props.onLeft(box)}
                        onRight={()=> this.props.onRight(box)}
                    ></Box>
                ))}
            </React.Fragment>
        );
    }
}
 

2.传递子节点
通过this.props.children属性传递子节点
在上面Boxes组件中,我们在Box标签中间插入了其它标签,就是我们通过children传入给Box的子结点。

Boxes中的父标签插入子节点:

 	 <Box key={box.id}>
             <h1>Box</h1>
             <p>#{box.id}</p>
	 </Box>

Box标签调用子节点:

class Box extends Component {
    state = { 
    };


    render() { 
        return (
            <React.Fragment>
                {this.props.children}
            </React.Fragment>
        );
    }
    
}

3.从下往上调用函数
注意:每个组件的this.state只能在组件内部修改,不能在其他组件内修改。
例:Boxes组件调用父组件App的函数:

<React.Fragment>  
        {this.props.boxes.map(box => (
          <Box 
              onDelete={this.props.onDelete}
              onLeft={() => this.props.onLeft(box)}
         	  onRight={()=> this.props.onRight(box)}
     		>
	       </Box>
		))}
</React.Fragment>

4.state数据的存储
每个维护的数据仅能保存在一个this.state
不要直接修改this.state的值,因为setState函数可能会将修改覆盖掉。
例如我们App组件中的handleClickLeft函数:

    handleClickLeft = (box) => {
        const boxes = [...this.state.boxes];    //这里浅拷贝一个数组
        const k = boxes.indexOf(box);            //索引box的下标
        boxes[k].x --;                            //修改box的x
        this.setState({boxes : boxes});        // 传给setState  为什么这里要大费周折复制一个数组在赋值呢? 如果直接修改
                   // state的值,可能会让DOM的数值不同步,因为react的DOM树需要setState才能更换,所以这样做可以使数据保持同步
    }

5.兄弟结点之间组件的调用
要将多个组件共用的数据存放到最近公共祖先的this.state中。

类似 Boxes和Navber 这两个组件,他们的公用数据都放在App组件中。

class App extends Component {
    state = { 
        boxes : [
            {id:1,x : 1},
            {id:2,x : 2},
            {id:3,x : 3},
            {id:4,x : 4},
        ]
     } 

     handleClickLeft = (box) => {
        console.log("handle click left");
        const boxes = [...this.state.boxes];    //这里浅拷贝一个数组
        const k = boxes.indexOf(box);            //索引box的下标
        boxes[k].x --;                            //修改box的x
        this.setState({boxes : boxes});        // 传给setState  为什么这里要大费周折复制一个数组在赋值呢? 如果直接修改
                   // state的值,可能会让DOM的数值不同步,因为react的DOM树需要setState才能更换,所以这样做可以使数据保持同步
    }
    handleClickRight = (box) => {
        console.log("handle click right");
        const boxes = [...this.state.boxes];
        const k = boxes.indexOf(box);
        boxes[k].x ++;
        this.setState({boxes : boxes});
    }

     handleReset = () => {
        const boxes = this.state.boxes.map(b=> {
            return {
                id: b.id,
                x : 0
            }
        });
        this.setState({boxes});
     }

     handleDelete = (boxId) => {
        const boxes = this.state.boxes.filter(
            b => b.id !== boxId
        );
        this.setState({boxes:boxes});
     }

    render() { 
        return (
            <React.Fragment>
                <NavBar  boxesCount={this.state.boxes.length}/>
                <Boxes 
                    boxes={this.state.boxes}
                    onReset={this.handleReset}
                    onLeft={this.handleClickLeft}
                    onRight={this.handleClickRight}
                    onDelete={this.handleDelete}
                />

            </React.Fragment>
        );
    }
}

6.无状态函数组件
当组件中没有用到this.state时,可以简写为无状态的函数组件。

以Navber组件为例:
类组件写法


class NavBar extends Component {
    state = {  } 
    render() { 
        return (
            <nav className="navbar navbar-light bg-light">
            <div className="container-fluid">
              <a className="navbar-brand">Navbar
                    <span>Boxes Count: {this.props.boxesCount}</span>
              </a>    
            </div>
          </nav>
        );
    }
}

函数组件写法 (函数的传入参数为props对象)

const NavBar= (props) => {
        return (
            <nav className="navbar navbar-light bg-light">
            <div className="container-fluid">
              <a className="navbar-brand">Navbar
                    <span>Boxes Count: { props.boxesCount}</span>
              </a>    
            </div>
          </nav>
        );
}

7.组件的生命周期
Mount周期,执行顺序:constructor() -> render() -> componentDidMount()
Update周期,执行顺序:render() -> componentDidUpdate()
Unmount周期,执行顺序:componentWillUnmount()

总结

Component是我们学习react的关键,掌握组件的方法就是迅速造几个简易的轮子来理解。在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老帅比阿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值