React.js笔记

184 阅读7分钟

React.js笔记

如何引入React

  • 从CDN引入React(可以通过 CDN 获得 React 和 ReactDOM 的 UMD 版本。)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

上述版本仅用于开发环境,不适合用于生产环境。压缩优化后可用于生产的 React 版本可通过如下方式引用:

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

如果需要加载指定版本的 reactreact-dom,可以把 16 替换成所需加载的版本号。

  • 通过webpack引入React(安装React、ReactDom)
yarn add react react-dom

使用import from 引入

import  React from 'react'
import reactDom from 'react-dom'

Create React App(脚手架)

Create React App 是一个用于学习 React 的舒适环境,也是用 React 创建新的单页应用的最佳方式。

它会配置你的开发环境,以便使你能够使用最新的 JavaScript 特性,提供良好的开发体验,并为生产环境优化你的应用程序。你需要在你的机器上安装 Node >= 8.10 和 npm >= 5.6。要创建项目,请执行:

  • 安装
yarn add create-react-app
  • 创建React项目
npx create-react-app my-app
cd my-app
npm start

React.createElement(创建React元素)

createElement(): 根据指定的第一个参数创建一个React元素。

  • 第一个参数是必填,传入的是似HTML标签名称,div: ul, li
  • 第二个参数是选填,表示的是属性,div: className
  • 第三个参数是选填, 子节点,div: 要显示的文本内容
import React from 'react'
const div = React.createElement('div',null,['我是div'])

ReactDom.render(渲染div到页面上)

ReactDom.render接收三个参数

  • 第一个参数,渲染的元素
  • 第二个参数,挂载的节点(元素要渲染到的节点)
  • 第三个参数,渲染完成后的回调函数
import React from 'react';
import ReactDOM from 'react-dom';
const div = React.createElement('div',null,['我是div'])
ReactDOM.render(
    div,
  document.getElementById('root')
);

React元素

createElement返回值element可以代表一个div元素

但是element并不是真正的div(DOM对象)

所以一般称element为虚拟DOM对象

()=> React元素

返回element函数,也可以代表一个div

这个函数可以多次执行,每次得到最新的虚拟DOM

React会对比两个虚拟DOM,找到不同局部更新视图

JSX

JSX 是 JavaScript 的语法扩展。它类似于模板语言,但它具有 JavaScript 的全部功能。JSX 被编译为React.createElement()返回称为“React 元素”的纯 JavaScript 对象的调用。

JSX简单实用

app.js

import React from "react";
const App = () => {
    return (
        <div className="div">
            爸爸
            <Son userNane="我是你爸爸"></Son>
        </div>
    )
}
class Son extends React.Component{
    constructor() {
        super();
        this.state = {n:0}
    };
    add(){
        this.setState({n:this.state.n+1})
    }
    render() {
        return (
            <div className="son">
                儿子 n :{this.props.userNane}
                <button onClick={()=>this.add()}>+1</button>
                <Grandson/>
            </div>
        )
    }
}
const Grandson =()=>{
    const [n, setN] = React.useState({n:1});
    return(
        <div className="Grandson">
            孙子n:{n.n}
            <button onClick={()=>setN({n:n.n+1})}>+1</button>
        </div>
    )
}
export  default App

main.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from "./app";

const div = React.createElement('div',null,['我是div'])
console.log(div)
ReactDOM.render(
    <App/>,
  document.getElementById('root')
);

React使用JSX要配置loader,jsx-loader就可以做到,实际上jsx-loader被babel-loader取代了,babel-loader有被微博pack内置了

JSX的使用

方法一: CDN

  • 引入babel.min.js
  • 把改成
  • babel会自动进行转译
  • 这种方法并不支持src

注意: 永远不要在生产环境中使用,因为效率太慢

方法二: webpack+babel-loader

方法三:使用create-react-app

  • 跟@vue/cli用法类似
  • 全局安装:
yarn global add create-react-app
  • 初始化目录
create-react-app react-demo (项目名称)
  • 打开项目
cd react-demo(项目目录)
yarn start

使用JSX的注意事项

  • 注意:元素添加类名使用(className)
const Div =()=> {
    return(
    	<div className="root">小明</div>    
    )
}

被转译为

React.createElement('div',{className:'root'},"小明")
  • 插入碧昂量

    标签里所有js代码都要用{}包起来

    如果你需要变量n ,那么就用{}把n包起来

    如果你需要对象,那么就要用{}吧对象包起来如{{ name:"小明" }}

    习惯return 后面加()

JSX的条件判断

  • 在React里
const Component = ()=>{
    return n%2 === 0?<div>n是偶数</div>:<span>n是奇数</span>
}
//如果外加div 可以成成这样
const Component = ()=>{
    return(
        <div>
            {n%2 === 0?<div>n是偶数</div>:<span>n是奇数</span>}
        </div>
    )
}
//还可以写成这样
const Component2 = ()=>{
    const content = (
        <div>
            {n%2 === 0?<div>n是偶数</div>:<span>n是奇数</span>}
        </div>
    )
    return content
}
  • 循环语句
const Component3 =(props)=>{
   return  props.array.amp((n,index)=>{
       return <diov>{n}下标是{index}</diov>
   })
}
//如果有div可以写成
const Component4 =(props)=>{
    return (
        <div>
            {
                props.array.amp((n,index)=>{
                   return <diov>{n}下标是{index}</diov>
                })
            }
        </div>
    )
}
//还可以这样写
const Component5 =(props)=>{
    const arr = []

    for(let i=0;i<props.array.length;i++){
        arr.push(<diov>{n}下标是{i}</diov>)
    }
    return <div>{arr}</div>
}

JSX就是在写JS

小总结

引入React & ReactDom

  • CDN方式:react.js 、react.dom.js、babel.js

React.createElement

  • 创建虚拟DOM对象
  • 函数的作用:对此创建虚拟DOM对象
  • DOM Diff 是什么

JSX

  • 将XML转译为React.createElement
  • 使用{}插入Js代码
  • create-reeact-app默认将js当做jJsx处理
  • 条件判断、循环要用原生js实现

React的类组件和函数组件

元素与组件

  • 元素
const div = React.createElement('div',null,"xiao")
这是一个React元素(d小写)
  • 组件
const Div = ()=>React.createElement('div',null,"xiao")
这是一个React组件(D大写)

函数组件

function Welcome(props){
    return <h2>hello {props.name}</h2>
}
//使用
<Welcome name="xiao"/>

类组件

class Welcome extends React.Component{
    render(){
        return <div>hell {this.props.name}</div>
    }
}
//使用
<Welcome name="xiao"/>

会被翻译成什么

  • 会被翻译为React.createElement("div")
  • 翻译为React.createElement("Welcome")

React.createElement的逻辑

  • 如果传一个字符串”div“,则会创建一个div
  • 如果传入一个函数,测绘条用该函数,获取器返回值
  • 如果传入一个类,测在类前面加一个new (这会导致执行constructor),获取一个组件对象,然后调用render方法,获取器返回值

添加props(外部数据)

  • 类组件直接读取属性this.props.xxx
class Div extends  React.Component{
    render(){
        return <div>hai {this.props.name}</div>
    }
}
  • 函数组件直接读取参数 props.xxx
const Div = (props)=>{
    return(
        <div>外部数据 {props.name}</div>
    )
}

添加state(内部数据)

  • 类组件用this.state读,this.setState写
class Div extends  React.Component{
    constructor() {
        super();
        this.state={
            n:1
        }
    }
    add(){
        this.setState({n:this.state.n+1})
        this.setState((state)=>{
            const n = state.n+1
          return {n}
        })
    }
    render(){
        return(
            <div>hai {this.state.n}</div>
        )
    }
}
  • 函数组件用useState返回数组,第一项读,第二项写
const Div = (props)=>{
    const [n,setN] = React.useState(0)
    return(
        <div>
            外部数据{n}
        <button onClick={()=>setN(n+1)}>+1</button>
        </div>
    )
}

类组件的注意事项

this.state.n +1= 无效?

  • 其实n已经改变了,只不过UI不会自动跟新而已
  • 调用setState才会触发UI更新(异步更新)
  • 因为React没有象Vue监听data一样监听state

setState会异步更新UI

  • setState之后,state不会马上给变,立马读state会失败
  • 更推荐的方式是setState(函数)

this.setState(this.state)不推荐使用

  • React希望我们不要修改就的state(不可变数据)
  • 常用代码:setState({n:state.n+1})

总结:这是一种理念(函数式)

函数组件注意事项

  • 给类组件类似的地方(也要通过setX(新值))来更新UI
  • 更类组件不同的地方(没有this,一律使用参数和变量)

复杂state

如果state里不止有n怎么办

  • 类组件里有n和m
class Div extends  React.Component{
    constructor() {
        super();
        this.state={
            n:1,
            m:2
        }
    }
    add(){
        // this.setState({n:this.state.n+1})
        this.setState((state)=>{
            const n = state.n+1
          return {n}
        })
    }

    render(){
        return(
            <div>
                n: {this.state.n} m:{this.state.m}
                <button onClick={()=>this.add()}>+1</button>
            </div>
        )
    }
}
  • 函数组件中有n和m

const Div = (props)=>{
    const [data,setData] = React.useState({
        n:0,
        m:0
    })
    // const [m,setm] = React.useState(0)
    return(
        <div>
            n:{data.n}m:{data.m}
        <button onClick={()=>setData({n:data.n+1})}>+1</button>
        </div>
    )
}

总结

  • 类组件的setState会自动合并第一层属性
  • 但是不会合并第二属性,要是用Object.assign或者...操作符
  • 函数组件的setX则完全不会帮你合并,要合并要用...操作符合并

事件绑定

类组件的事件绑定

<button onClick={()=>this.addN()}>N+1</button>

注意:传一个函数给onClick即可,注意C大写

<button onClick={this.addN()}>N+1</button>

注意:有问题,这样会使得this.add里的this变成window

<button onClick={this.addN.bing(this)}>N+1</button>

注意:这样写是可以的,因为它返回了一个

绑定了当前this的新函数,但是这样写太麻烦

//可以this._addN=()=>this.addN()给箭头函数区个名字
<button onClick={this._addN}>N+1</button>

类组件的事件绑定最终写法

class Sot extends React.Component{
    constructor() {
        super();
        this.state = {
            n:0
        }
    }
    add = ()=>{
       this.setState({n:this.state.n+1})
    }
    render(){
        return (
            <div>
                n:{this.state.n}
                <button onClick={this.add}>+1</button>
            </div>
        )
    }
}

上面代码中add等价于constructor中的add

class Sot extends React.Component{
    ...
    add = ()=>{
       this.setState({n:this.state.n+1})
    }
    add1(){
        this.setState({n:this.state.n+1})
    }
...
}

上面代码中add和add1的区别

  • add函数是对象本身的属性,这意味着每个Sot组件都有自己的add,如果有两个Sot,j就有两个add
  • add1函数是对象的功用属性(也就是原型上的属性),这样所有Sot组件功用一个add1

函数组件绑定事件

const Div = (props)=>{
    const [n,setN] = React.useState(0)
    const [m,setM] = React.useState(0)

   const got = ()=>{
        console.log(222)
   }
    return(
        <div>
            n:{n}m:{m}
        <button onClick={()=>setN(n+1)}>+1</button>
            <button onClick={()=>got()}>按钮</button>
            <button onClick={got}>按钮2</button>
        </div>
    )
}

为什么this会变/不会变

  • 所有的函数的this都是参数,由调用决定,所以可改变
  • 维度箭头函数的this不变,因为头函数不接受this

关于this的三篇文章

总结

关于React的知识点

  • 另种方式引入React&ReactDOM
  • React.createrElement("div"|函数|类)
  • 类组件,函数组件如何获取外部数据props
  • 类组件、函数组件如何使用内部数据state
  • 类组件如何绑定事件
  • 函数组件绑定事件非常简单不用this,使用函数