React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)

思考一个问题:
之前我们讲到过,使用props传递的值不能动态修改。如果我们想要实现数据动态更新,该怎么办呢?或者更详细点说,如何根据用户操作、网络响应、或者其他状态变化,使组件动态的响应并改变组件的输出呢。

这个时候引入react的state状态机概念。

State 状态机


React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。

React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。


摘自菜鸟教程:https://www.runoob.com/react/react-state.html

组件被称之为"状态机",视图与状态一一对应。

在react中开发者只需要关心数据,数据改变页面就会发生改变。数据等同于状态。当状态改变时,页面绑定的数据就由react进行改变。

(1)初始化状态

使用状态必须先初始化,不过初始化的方式不止一种,视具体场景变化而不同。https://blog.csdn.net/weixin_43297321/article/details/108167262

不过这次我们在类组件的constructor中完成state的初始化,语法:this.state={}

React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第1张图片

constructor与super

由ES6的继承规则可知,不管子类写不写constructor,在new实例的过程都会给补上constructor。

" 可以不写constructor,一旦写了constructor,就必须在此函数中写super(),super调用父类的构造方法,此时组件才有自己的this,可以在组件的全局中使用this关键字。否则如果只是constructor而不执行super() 那么以后的this都是错的!!!super()继承父组件的 this 。"
在这里插入图片描述

super(props)

当想在constructor中使用this.props的时候,super需要加入(props)。

此时用props也行,用this.props也行,他俩都是一个东西。(不过props可以是任意参数,this.props是固定写法)

我说:反正,在使用state的时候,就把constructor和super加上。

(2)读取状态

读取状态:this.state.key

React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第2张图片

(3)更新状态

组件界面更新:this.setState({},()=>{})

小知识:setState()直接使用是异步的,会自动触发render函数的重新渲染,而且既然是异步的,就应该有回调函数,可以把要跟着这个函数一起处理的逻辑写在回调函数里;不过如果是在setTimeout或者DOM事件中使用,那么setState()是同步的。

setState是同步还是异步:https://www.kancloud.cn/freya001/haoke/1687601

简书:Component.setState()详解
简书:关于this.setState()的那些事

React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第3张图片

(4)完整使用

实现的内容:

  • state渲染html
  • 当输入框输入的内容改变时,同步展示输入框值的改变(建议用onInput事件)
<div id="demoSky">div>
<script type="text/babel">
    class Fu extends React.Component{
        constructor(props){
            super(props);
            this.state={
                html:"

I'm a target.

"
, inputVal:"" } } fun=(e)=>{ console.log(e.target.value); this.setState({ inputVal:e.target.value },()=>{}) } render(){ return( <div> <h4>输入的是:{this.state.inputVal}</h4> <input type="text" onInput={this.fun}/> {/* state渲染html,双底杠 __*/} <p dangerouslySetInnerHTML={{__html:this.state.html}}></p> </div> ) } } ReactDOM.render(<Fu/>,document.querySelector("#demoSky"))
script>

React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第4张图片

(5)扩展

>> this.setState()是异步的

React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第5张图片

如果想看到修改后的值,就在setState回调函数中查看。
React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第6张图片

>> 插入字符串标签

如果我们想解析一个字符串类型的标签,如何?
React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第7张图片
直接打印是下面这个样子的:
React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第8张图片

可以使用react给我们提供的方法dangerouslySetInnerHTML = {{ __html:你要插入的字符串 }}

React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第9张图片

>>问题:为什么不用工厂方式创建组件了?

在有状态的前提下,不能使用工厂方式创建组件。

怎么通过工厂模式创建组件:https://blog.csdn.net/teamlet/article/details/78797386


受控组件


受控组件就是可以被 react 状态控制的组件
在 react 中,Input textarea 等组件默认是非受控组件(输入框内部的值是用户控制,和React无关)。但是也可以转化成受控组件,就是通过 onChange 事件获取当前输入内容,将当前输入内容作为 value 传入,此时就成为受控组件。
好处:可以通过 onChange 事件控制用户输入,使用正则表达式过滤不合理输入。

链接:https://www.jianshu.com/p/c4fb11f42252

然后看这篇:react中的受控和非受控组件https://www.cnblogs.com/wasbg/p/11142074.html


Refs 转发


React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。

这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例。


简书:https://www.jianshu.com/p/64a9cfdf72ca

React提供的这个ref属性,表示为对组件真正实例的引用。其实就是ReactDOM.render()返回的组件实例。(ref属性不能在无状态组件上使用 ref 属性,因为它们没有实例)

ReactDOM.render()渲染组件时返回的是组件实例;而渲染dom元素时,返回是具体的dom节点。

一句话总结:标识组件内部的元素


React 的 ref 有 3 种用法:

  1. 字符串 (官方不推荐使用)
  2. 回调函数(官方推荐)
  3. React.createRef() (React16.3新提供)

(1)ref 使用方法一:字符串

这种方法是最早的ref用法。通过this.refs.xxx来进行访问。(官方不推荐使用)

<div id="demoSky">div>
<script type="text/babel">
   class Fu extends React.Component {
       constructor(props) {
           super(props);
           this.state = {
             value:""
           }
       }
       fun=()=>{
           // console.log("输入框的值:",this.refs.inputa.value)
           this.setState({
               value:this.refs.inputa.value
           })
       }
       render() {
           return (
               <div>
               <h1>ref字符串的方式</h1>
                 <input type="text" ref="inputa"/><button onClick={this.fun}>点击</button>
                 <p>{this.state.value}</p>
               </div>
           )
       }
   }
   ReactDOM.render(<Fu />, document.querySelector("#demoSky"))
script>

React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第10张图片


(2)ref 使用方法二:回调函数

回调函数就是在dom节点或组件上挂载函数,函数的入参是dom节点,达到的效果与字符串形式是一样的,都是获取其引用。(官方推荐)

React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第11张图片
React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第12张图片


(3)ref 使用方法三:React.createRef()

在React 16.3版本后,使用此方法来创建ref 。将其赋值给一个变量,通过ref挂载在dom节点或组件上该ref的current属性将能拿到dom节点或组件的实例。(React16.3新提供,常用)

React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第13张图片

React note4(State&受控组件&ref&组件生命周期&事件&this的绑定)_第14张图片


官方建议

不要过度使用 Refs,在对逻辑进行处理的时候尽量优先考虑state。因为考虑到代码耦合度以及后期的维护。


React受控组件


React负责渲染表单的组件。同时仍然控制用户后续输入时所发生的变化。值是来自于state控制的,输入表单元素称为“受控组件”。

segmentfault:https://segmentfault.com/a/1190000012404114


React组件生命周期


每个组件都包含 " 生命周期方法 ",可以重写这些方法,以便于在运行过程中特定的阶段执行这些方法。

React 生命周期分为三种状态:
  • 挂载阶段
  • 更新阶段
  • 卸载阶段
React 生命周期纵览

生命周期的相关方法:

  • componentWillMount 组件渲染之前调用
  • componentDidMount 组件渲染之后调用在第一次渲染后调用

  • componentWillUpdate 组件即将更新html时候调用
  • componentDidUpdate 在组件完成更新后立即调用。

  • componentWillUnmount 在组件从 DOM 中移除之前立刻被调用。
  • ReactDOM.unmountComponentAtNode(document.getElementById(“demodiv”)); //卸载组件

  • shouldComponentUpdate 判定组件是否要更新html
  • componentWillReceiveProps 在组件接收到一个新的prop时被调用。这个方法在初始化render时不会被调用。

菜鸟教程:https://www.runoob.com/react/react-state.html


React事件处理


(1)语法

React事件绑定属性的命名采用小驼峰式写法。

绑定函数的过程中不加(),否则函数会立即执行。

<button onClick={this.fun}>点我</button>

(2)阻止默认行为

React中阻止默认行为使用 preventDefault(),是不是跟原生js里的一样。

(3)修改this指向(面试常问)

如果遇到this绑定失效的问题,整理出四种方法。

方式1:通过bind方法进行原地绑定,从而改变this指向

方式2:通过创建箭头函数

方式3:在constructor中提前对事件进行绑定

方式4:将事件调用的写法改为箭头函数的形式

<div id="demoSky">div>
<script type="text/babel">
    class Fu extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                name:"sky"
            }
            // 在constructor中提前绑定this
            this.fun3=this.fun3.bind(this);
        }
        fun1(){
            this.setState({
                name:"bind绑定this:this.fun1.bind(this)"
            })
        }
        fun2=()=>{
            this.setState({
                name:"箭头函数的方式绑定this"
            })
        }
        fun3(){
            this.setState({
                name:"在constructor中提前绑定this:this.fun3=this.fun3.bind(this);"
            })
        }
        fun4(){
            this.setState({
                name:"使用箭头函数的方式进行函数的调用来绑定this:()=>{this.fun4()}"
            })
        }

        render() {
            return (
                <div>
                <p>{this.state.name}</p>
                    <button onClick={this.fun1.bind(this)}>bind绑定this</button>
                    <button onClick={this.fun2}>箭头函数绑定this</button>
                    <button onClick={this.fun3}>在constructor中提前绑定this</button>
                    <button onClick={()=>{this.fun4()}}>使用箭头函数的方式,进行函数的调用来绑定this</button>
                </div>
            )
        }
    }
    ReactDOM.render(<Fu />, document.querySelector("#demoSky"))
script>

在这里插入图片描述

(4)传递参数

向事件处理函数中传递参数。

方式1(推荐):通过 bind 的方式进行传递。

在这里插入图片描述
方式2:通过箭头函数传递。注意:使用箭头函数调用的话,事件对象必须显式的进行传递(不需要,也可以不写事件对象)。
在这里插入图片描述

<div id="demoSky">div>

<script type="text/babel">
    class Fu extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                name:"sky"
            }
        }

        fun(text){
            // console.log(text)
            this.setState({
                name:text
            })
        }

        render() {
            return (
                <div>
                    <h4>{this.state.name}</h4>
                    <button onClick={this.fun.bind(this,"传递给函数的实参")}>bind方式传递参数</button>
                    <button onClick={()=>this.fun("箭头函数传参")}>箭头函数方式传递参数</button>
                </div>
            )
        }
    }
    ReactDOM.render(<Fu />, document.querySelector("#demoSky"))
script>

在这里插入图片描述


总结


注意几个问题:

(1)this指向,谁最后调用它,就指向谁。

(2)使用状态机的话,一般情况下,不能使用无状态组件,因为它不能创建实例。但后期可以通过hook来实现。

(3)state是异步的,所以可以在回调函数中写一些处理逻辑,this.setState({},()=>{})

你可能感兴趣的:(React,笔记,非原创,react)