React全家桶学习笔记 (一)

React全家桶学习笔记 (一)

一、jsx基本语法

(react核心库 react , react-dom(虚拟dom), babel(jsx转js))
一.定义虚拟dom时不要使用引号
二.标签使用表达式使用{}
(1)在{}中只能写表达式(注意:语句与表达式的区别)

  • (一)表达式:一个表达式会产生一个值

    	例:
            1.a 
            2.a+b,
            3.a(),
            4.arr.map(),
            5.function a(){}
    
  • (二)语句:

         例:
             1.if(){}else{}
             2.for(){},
             3.switch(){case xx : xxx}
    

三.样式类名使用className(不使用class,避免与es6中类的命名冲突)
四.内联样式,使用style={{key:value}}
五.jsx中虚拟DOM只允许有一个根标签
六.标签必须闭合
七.标签首字母如果是小写字母开头则是普通HTML标签, 如果是大写字母开头则是一个组件

二、组件

在react中组件分为两种,函数组件 , 类组件。
函数组件的函数名就是组件名,类组件的类名就是组件名。

1.函数组件

    function MyFun(){
        return (
            <span>我是函数组件</span>
        )
    }

2.类组件

在讲类组件之前需要先了解一些关于es6中类的基础知识

class Person{
    constructor(a,b){//构造器
        // 构造器中的this指的是实例对象(谁new()了就指向谁,构造器中的属性都是私有的)
        this.a = a;
        this.b = b;
    }
    // 1.方法是公有的 是放在这个类上的 
    // 2.通过实例调用方法时,方法中的this指向实例对象
    eat(){
        console.log('我想吃饭'+this.a);
        // console.log(this);
    }
    run(){
        console.log(this);
    }
}
let p1 = new Person(1,2);
let p2 = new Person(3,4);
// console.log(p1); //Person { a: 1, b: 2 }
// console.log(p2); //Person { a: 3, b: 4 }

p1.eat(); //我想吃饭1
// p2.eat(); //我想吃饭3


// 类中的继承
class Car extends Person{
    constructor(a,b,price){
        super(a,b);//如果Car继承于Person 写状态机时必须使用super来接收父类中的属性 super必须放在最前面
        this.price = price;
    }
}

let c1 = new Car('宝马','五系');
let c2 = new Car('奥迪','rs6')
let c3 = new Car('奔驰','s级','200w')
// console.log(c1); //Car { a: '宝马', b: '五系' }
// console.log(c2); //Car { a: '奥迪', b: 'rs6' }
// console.log(c3); //Car { a: '奔驰', b: 's级', price: '200w' }
// c3.eat(); //我想吃饭奔驰 eat方法继承于父类中的方法(原型链 通过 _proto_ 连接) 


// 在类中是可以直接写赋值语句的
class Food{
    constructor(name){
        this.name = name 
    }
    age=18//实例对象上
    static type=1 //直接将type写到实例上
}
let f1 = new Food('小明');
console.log(f1);//Food { age: 18, name: '小明' }
console.log(Food);//[class Food] { type: 1 }
(1).类组件必须继承 
(2).且必须有render 
(3).render必须有返回值 , 你想渲染什么就返回什么
 class MyFunTwo extends React.Component{
    render(){ 
         return(
             <span>我是类组件</span>
         )
     }
 }
 ReactDOM.render(<MyFunTwo/>,document.getElementById(''));
}

3.函数组件与类组件的区别

1.函数组件中没有this 类组件有
2.函数组件中没有生命周期 类组件有
3.函数组件中没有状态state(新增hooks) 类组件有

组件分为简单组件和复杂组件(有状态组件又称复杂组件),当状态机发生改变时,组件会重新渲染

三、组件的三大核心属性

在react中组件内会自带三大属性props:{} refs:{} state:null 这些值都在组件的实例上

1.state

state是组件中一个很重要的属性,可以包含多个key:value,是组件中的状态机 state必须是一个对象。

class MyFunTwo extends React.Component{
    constructor(props){
        super(props);
        this.state = {
        	isMen:true
        }
    }
    render(){
     return (
         <span>{this.state.isMen?'是':'不是'}函数组件</span> 
         //这里的this与constructor中的this都指向react内new的实例对象(组件的实例对象)
     )
}

状态的修改
注意:组件中的状态(state)不能直接修改,需要使用内置API --setState
setState是一个合并的操作 不是覆盖

class MyFunTwo extends React.Component{
           constructor(props){
               super(props);
               this.state = {
                   isMen:true,
                   number:0
               }
               this.demo = this.demo.bind(this); //修改demo的this指向 否则将会是undefined
           }
           demo(){
               console.log(this.state.isMen) //true
               if(this.state.number == 0){
                   this.setState({
                       number:1,
                   })
               }else{
                   this.setState({
                       number:0,
                   })
               }
           }
           render(){
               return (
                   <span onClick={this.demo}>{this.state.isMen?'是':'不是'}函数组件{this.state.number}</span> 
                   //这里的this与constructor中的this都指向react内new的实例对象,
                   //因为demo方法是挂载在实例下所以这里要使用this.demo才能访问到,
                   //注意:此处的demo不要加()否则render会直接执行此函数并return一个undefined

               )
           }
       }
       ReactDOM.render(<MyFunTwo/>,document.getElementById('test'));
       //简写方式
	 class MyFunTwo extends React.Component{
	            state={
	                Number:1
	            }
	
	            demo=()=>{
	                this.setState({
	                    Number:2
	                })
	            }
	            render(){
	                return (
	                    <span onClick={this.demo}>{this.state.Number}</span> 
	                )
	            }
	        }
	        ReactDOM.render(<MyFunTwo/>,document.getElementById('test'));

state总结:
1.在组件render中的this指向实例对象
2.组件中自定义的方法中this指向undefined 解决方案(通过bind改变this 、箭头函数)。
3.状态不能直接修改,需要使用setState({key:value})

2.props

主要用于接收组件外部传入的数据
1.类组件使用props

class MyFunTwo extends React.Component{
    state={
        Number:1,
        name:''
    }
    

    demo=()=>{
        const {name} = this.props; //接受传过来的props值
        this.setState({
            Number:2,
            name,
        })
    }
    render(){
        return (
            <span onClick={this.demo}>{this.state.Number}{this.state.name}</span> 
        )
    }
}
ReactDOM.render(<MyFunTwo name='张三'/>,document.getElementById('test'));
//如果数据过多就会显得很繁琐,这时候可以使用展开运算符
//ReactDOM.render(<MyFunTwo {...data}>,document.getElementById('test'));

2.函数组件使用props

// 函数组件使用props
function Funcprops(props){
   console.log(props);
   return(
       <>
           <span>函数接收props{props.name}</span>    
       </>
   )
}
ReactDOM.render(<Funcprops name='张三'/>,document.getElementById('test'));

如果需要对props的数据类型进行限制则需要使用propTypes(在16版本以后被弃用了,如果需要使用需要下载依赖)
注意:props是只读的

3.refs

refs的作用是拿到被标记的节点
1.字符串形式的refs(不推荐使用–效率不高)

class Demo extends React.Component{
      click = ()=> {
          const {input1} = this.props.refs;
          console.log(input1.value);
      }
      render(){
          return(
              <>
                  <input ref = 'input1' type="text" placeholder="请输入姓名" />
                  <button onClick={this.click}>xx</button>
                  <input type="text"  placeholder="请输入年纪"/>
              </>
          )
      }
  }
  ReactDOM.render(<Demo name='张三'/>,document.getElementById('test'));

2.回调函数的refs
如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。

class Demo extends React.Component{
    click = ()=> {
        const {input1} = this;
        console.log(input1.value);
    }
    render(){
        return(
            <>
                <input ref = { currentNode => this.input1 = currentNode  } type="text" placeholder="请输入姓名" />
                <button onClick={this.click}>xx</button>
                <input type="text"  placeholder="请输入年纪"/>
            </>
        )
    }
}
ReactDOM.render(<Demo name='张三'/>,document.getElementById('test'));

//内联函数问题展示
class Demo extends React.Component{
    state={
        isMen:true
    }
    click = ()=> {
        const {input1} = this;
        const { isMen } = this.state;
        this.setState({
            isMen:!isMen
        });
    }
    render(){
        const { isMen } = this.state;
        return(
            <>
                <span>{isMen?'是':'不是'}一个男孩子</span>
                <input ref = { currentNode => {this.input1 = currentNode;console.log('@',currentNode) } } type="text" placeholder="请输入姓名" />
                <button onClick={this.click}>xx</button>
            </>
        )
    }
}
ReactDOM.render(<Demo name='张三'/>,document.getElementById('test'));

在这里插入图片描述
解决上述问题的写法-绑定函数的方式

        class Demo extends React.Component{
            state={
                isMen:true
            }
            click = ()=> {
                const {input1} = this;
                const { isMen } = this.state;
                this.setState({
                    isMen:!isMen
                });
            }

            inputFunc = (currentNode)=>{
                const {input1} = this;
                this.input1 = currentNode;
                console.log('@',currentNode)
            }
            render(){
                const { isMen } = this.state;
                return(
                    <>
                        <span>{isMen?'是':'不是'}一个男孩子</span>
                        <input ref = {this.inputFunc} type="text" placeholder="请输入姓名" />
                        <button onClick={this.click}>xx</button>
                    </>
                )
            }
        }
        ReactDOM.render(<Demo name='张三'/>,document.getElementById('test'));

3.createRef(推荐使用)
React.createRef();调用后会返回一个容器,该容器可以存储ref所标识的节点。
注意:只能存储一个

class Demo extends React.Component{
    demoRef = React.createRef();

    inputFunc = ()=>{
        console.log(this.demoRef.current.value);
    }
    render(){
        return(
            <>
                <input ref = {this.demoRef} type="text" placeholder="请输入姓名" />
                <button onClick={this.inputFunc}>xx</button>
            </>
        )
    }
}
ReactDOM.render(<Demo name='张三'/>,document.getElementById('test'));

四、受控组件与非受控组件

1、受控组件

在 HTML 中,表单元素(如、 和 )通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
通过事件去改变状态state的叫受控组件 类似于vue中的双向数据绑定

//受控组件
class Index extends React.Component {
     state = {
         username:''
     }
     submit = (e) => {
         e.preventDefault();
         console.log(this.state.username);
     }
     changeUser = (e)=>{
         this.setState({
             username:e.target.value,
         })
     }
     render(){
         return(
             <>
                 <form onSubmit={this.submit}>
                     用户名:<input onChange={this.changeUser} type="text"/> 
                     <button>登陆</button>
                 </form>
             </>
         )
     }
 }

2、非受控组件

要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。
现用现取就是非受控组件

 class Index extends React.Component {
     submit = (e) => {
         e.preventDefault();
         console.log(this.username.value);
     }
     render(){
         return(
             <>
                 <form onSubmit={this.submit}>
                     用户名:<input ref = {currentNode =>{ this.username = currentNode}} type="text"/> 
                     <button>登陆</button>
                 </form>
             </>
         )
     }
 }

五、生命周期

旧版本的生命周期
在这里插入图片描述

  • 1.组件初始化阶段

    • (1)constructor() 构造器
    • (2)componentWillMount() 组件将要挂载
    • (3)render() 渲染
    • (4)componentDidMount() 组件完成挂载 ->常用(一般用于初始化的事件 ,例如:数据请求,定时器,订阅消息)
  • 2.组件更新阶段 / 父组件render

    • (1)shouldComponentUpdate() 组件是否将要更新 返回true或者false
    • (2)componentWillUpdate() 组件将要更新
    • (3)render() 渲染
    • (4)componentDidMount() 组件完成挂载
  • 3.卸载组件(由ReactDOM.unmountComponentAtNode()触发)

    • (1)componentWillUnmount() 组件将要卸载 ->常用(删除定时器,取消订阅)

forceUpdate()强制更新 (很少使用)
新版本生命周期
在这里插入图片描述
相比老版本的生命周期 ,新版本的生命周期中减少了componentWillMount,componentWillUpdate,componentWill ReceiveProps 新增了getDerivedStateFromProps,getSnapshot BeforeUpdate。

static getDerivedStateFromProps(){}如果state的值在任何时候都取决于props那么你可以使用这个钩子 必须返回state或者null 否则会报警告 ,但是可能会导致代码冗余–不推荐使用此钩子

getSnapshotBeforeUpdate(prevProps, prevState) 在最近一次渲染输出(提交到 DOM 节点)之前调用。应返回 snapshot 的值(或 null)。此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。

六、DOM的diff算法

react在渲染组件到页面时会先生成虚拟DOM再转成真实DOM渲染到页面,在更新时会先对比虚拟DOM(每一个虚拟DOM对应一个虚拟DOM),它会将新的虚拟DOM与旧的虚拟DOM进行一次对比,再将新的虚拟DOM转换为真实DOM,如果对比发现没有区别即真实DOM不会发生改变。

七、key的作用

1.虚拟DOM中key的作用:
当状态中的数据发生改变时,react会根据新数据生成新的虚拟DOM,随后react进行新虚拟DOM与旧虚拟DOM的diff比较。
1.虚拟DOM中key的作用

  • 旧虚拟DOM中找到了与新虚拟DOM相同的key
    • 若虚拟DOM中的内容没变,直接使用之前的真实DOM
    • 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换之前页面中的真实DOM
  • 旧虚拟DOM中未找到与新虚拟DOM相同的key
    • 根据数据创建新的真实DOM,随后渲染到页面

2.用index作为key可能引发的问题

  • 1.若对数据进行:逆序添加,逆序删除等破坏顺序操作(会产生没有必要的真实DOM更新 ,界面效果没有问题,但是效率很低)
  • 2.如果结构中还包含输入类的DOM input等(会产生错误DOM更新,界面有问题)
 class Demo extends React.Component {
            state = {
                data:[
                    {id:1,name:'张三'},
                    {id:2,name:'王五'}
                ]
            }
            clickFunc = ()=>{
                const {data} = this.state;
                const newDate = {id:3,name:"李四"}
                this.setState({
                    data:[newDate,...data]
                })
            }
            render(){
                return(
                    <>
                        {
                            this.state.data.map(i => {
                                return <li key={i.id}>我的名字叫{i.name}</li>
                            })
                        }
                        <button onClick={this.clickFunc}>点我</button>
                    </>
                )
            }
        }
        ReactDOM.render(<Demo />,document.getElementById('test'));

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

class Demo extends React.Component {
            state = {
                data:[
                    {id:1,name:'张三'},
                    {id:2,name:'王五'}
                ]
            }
            clickFunc = ()=>{
                const {data} = this.state;
                const newDate = {id:3,name:"李四"}
                this.setState({
                    data:[newDate,...data]
                })
            }
            render(){
                return(
                    <>
                        {
                            this.state.data.map((item,index) => {
                                return <li key={index}>我的名字叫{item.name}<input type="text"/></li>
                            })
                        }
                        <button onClick={this.clickFunc}>点我</button>
                    </>
                )
            }
        }

在这里插入图片描述
点击之后会导致输入内容与li内容显示不匹配问题
在这里插入图片描述
持续更新ing…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>