React组件:React 类组件和函数组件

362 阅读5分钟

学习内容:

    1. 类组件和函数组件
    1. 如何使用props和state
    1. 如何绑定事件
    1. 复习this和两个面试题

一、类组件和函数组件

前提知识:

1.什么是组件?

可以和其他东西结合起来的物件

2.元素与组件

  • element component
  • 一个返回React元素的函数就是组件
  • React中的元素: 变量名小写
const app = React.createElement('div',……)
  • React中的组件 : 变量名大写
const App = ()=> React.createElement('div',……)

React组件初体验

React中有两种组件:一个是类组件,一个是函数组件

  • 函数组件
//定义函数组件
function Welcome(props){
    return (<h1>Halo,{props.name}</h1>)
}
//使用组件
<Welcome name='Yuyuan'/>
  • 类组件
//定义类组件
Class Welcome extends React.Component{
    render(){
        return (<h1>Halo,{this.props.name}</h1>)
    }
}

//使用类组件
<Welcome name='Yuyuan'/>

<Welcome />的理解

<Welcome />是XML语法,它对应的JS语法是什么样子?

1. 借助工具进行翻译

在线转义工具:babel online

转义代码:

<div></div>;

<div className='red'>halo</div>;

<App name='Yuyuan' />;

const App_01 = ()=>{
	return <h1>halo</h1>
} ;

const App_02 = (props)=>{
	return (<h1>halo,{props.name}</h1>)
} 
<App_02 name='Yuyuan' />;
;

class App_03 extends React.Component{
  constructor(){
  	super()
  	this.state = {n:0}
  }
  render(){
  	return <div>hi</div>
  }
}

<App_03 name='hi'/>

2. 转义结果解释

  • 首先,<div />,<Welcome />都会被翻译成React.createElement('div or Welcome')
  • 然后对于React.createElement而言,
    • 如果传入一个字符串'div',则会创建一个div
    • 如果传入一个函数,则会调用该函数获取其返回值
    • 如果传入一个类,则会在类前面加个new(这会导致执行construcor),获取一个组件对象,然后调用对象的render方法,获取其返回值

组件使用的小练习

React组件初使用完整代码

前置知识:

  • 函数组件和类组件的定义使用,React虚拟DOM元素的定义使用
  • {}的使用
  • 如何使用props(外部数据,如何使用state(内部数据 (见下文)
  • 析构赋值 const [n,setN]=React.useState(0)等价于 arr=React.useState(0);n=arr[0];setN=arr[1]

代码复写:

import React from 'react';
import ReactDOM from 'react-dom';

function App(){
    return (<div className='grandpa'>爷爷<Dad /></div>)
}

class Dad extends Component{
    constructor(){
        super()
        this.state = {n:0}
    }
    add(){
        this.setState({n:this.state.n+1})
    }
    render(){
        <div className='dad'>爸爸 n : {this.state.n}
            <button onClick={()=>this.add()}>
                +1
            </button>
            <Son />
        </div>
    }  
}

Son = ()=>{
    const [n,setN] = React.useState(0)
    return (
        <div className='son'>儿子 n :{n} 
            <button onClick={()=>setN(n+1)>
                +1
            </button>
        </div>
    )
}

ReactDOM.render(<App />,document.getElementById('root'))

bug:

  • js中使用jsx报错 :/src/index.js: Support for the experimental syntax
    • 错误原因:弄混了<scipt>引入法和webpack自带法,scr引入只能写在scr type中,webpack自带的babel-loader可以在js中直接写。
    • 解决方法:在codesanbox中新建一个react文件就行了,import引入React和ReactDOM

二、如何使用props和state

1. 添加props外部数据

React使用props示例

  • 定义外部数据:<变量名>=<数据> props_01='你爷爷的'数据 可以是字符串也可以是{js变量},是在组件被使用的时候定义的。
  • 使用外部数据:class中使用前面加上this,props.<变量名> props.props_01
    import React from 'react';
    import ReactDOM from 'react-dom';
    
    function App(){
        return (<div className='grandpa'>爷爷<Dad props_01='你爷爷的'/></div>)
    }
    
    class Dad extends React.Component{
        render(){
            return (
                <div className='dad'>爸爸,{this.props.props_01}<Son props_02={1+1} /></div>
            )
        }
    }
    
    const Son = (props)=>{
        return (
            <div className='son'>儿子,{props.props_02}</div>
        )
    }

2. 添加state内部数据

  • state的使用分为类组件和函数组件
  • 案例就是本文中的React组件使用案例中的例子,此处对state的使用进行解释和说明。

添加state使用说明的小案例

A.在类组件中

a.使用state:
  • state的初始化 this.state={n:0} 在constructor中,super()之后
  • state的读取 {this.state.n}
  • state的写入
    • this.setState({n:this.state.n+1})
    • this.setState(state=>{return {n : state.n+1}})
b.注意事项:
  • React无法自动监听n的变化,所以更改数据时,this.state.n+=1是无效代码,要使用setState去监听
  • setState不会立刻刷新UI,而是会异步刷新,因此立刻去读state中的值不会是最新的值,推荐使用setState(函数)方法
  • setState参数不要只写变化后的值,推荐写对象,这样就不会更改原来数据的值,而是会新分配地址去存储,this.setState({n:this.state.n+1})

B.在函数组件中

a.使用state

const [n,useN]=React.useState(0)

  • React.useState接受的参数是初始值,返回一个数组,数组第一项读,第二项写。
  • n:{n}onClick={()=>useN(n+1)}
b.注意事项:
  • 更新UI,需要通过useState返回的第二项
  • 不使用this

C.复杂state的处理

a.类组件中的复杂state
  • 初始化:this.state={n:0,m:0},写一个state的初始化就行了
  • 读值:和简单的state读值一样
  • 写入:另外写一个函数写另外的state如何变化
    • diff检测到变化比较时,第一层属性不会合并,更改m不会覆盖n的值为undefined
    • 相当于return { ...state, m: state.m + 2 };这样继承了n值
b.函数组件中的复杂state
  • 可以定义多个React.useState来写复杂组件,如案例中的son函数部分
const Son = () => {
    const [n, stN] = React.useState(0);
    const [m, stM] = React.useState(0);
    return (
        <div className="son">
            儿子 n :{n}
            <button onClick={() => stN(n + 1)}>+1</button>m : {m}
            <button onClick={() => stM(m + 3)}>+3</button>
        </div>
    );
};
  • 可以只定义一个React.useState,但是读值要指定,写值要继承。这里不会智能合并。
const Grandson = () => {
    const [state, setState] = React.useState({ n: 0, m: 0 });
    return (
        <div className="grandson">
            老弟 n :{state.n}
            <button onClick={() => setState({ ...state, n: state.n + 1 })}>+1</button>
            m : {state.m}
            <button onClick={() => setState({ ...state, m: state.m + 5 })}>+5</button>
</div>
);
};
c.两层属性在类组件和函数组件之中都不会自动合并
//初始化
this.state = {
    n:0,
    m:0;
    user:{name:'yuyuan',age:18}
}

//改值不会继承 错误改值
change(){
    this.setState({user:{name:'fuck'}})
}

//改值第一种方法 继承
changeClass(){
    this.setState({...this.state.user,user:{name:'fuck01'}})
}

//改值第二种方法 复制
changeAss(){
    const user = Object.assign({},this.state.user)
    user.name='fuck03'
    this.setState({user:user})
}
error:

总是在各种语法上写出各种错误,例如: this.setState({...this.state.user,user:{name:'fuck01'}})这一句可以写出n个错误:

  • 把继承的不和user写在一级,继承的不写this
  • 里面要更改的user写this
  • user:{name}要写成user.name
  • 外面的函数硬要写成return this.setState(),然后setState中写函数又忘记写return
  • ……

三、React绑定事件的各种写法

  • 用函数组件直接躲过与this的交锋
  • 绑定事件最麻烦的是this会绕来绕去,但是我目前this还绕不清楚,因此,直接写结论吧。
  • (this博客待写) this学习推荐文档

绑定事件简约写法

//定义函数
addMN = ()=>{
    this.setState({n:this.state.n+1})
}

//绑定事件
onClick={this.addMN}

裹脚布:

事件绑定各种写法.png

事件绑定写法过渡.png

事件绑定最终写法.png

四、this的面试题

解题要点:

  • 先动手,不要用脑袋去理解,理解也理解不了
  • 动手,遇到函数调用直接改写成call形式,null的this即为window。

题1:

this面试题1.png

改写版面试题1.png

题2:

this面试题2.png 10 2

改写版面试题2.png

总结

知识点总结简短版.png

React VS Vue.png