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>
如果需要加载指定版本的 react 和 react-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,使用函数