安装
CDN引入React
不推荐
Reacrt(https://cdn.bootcss.com/react/16.10.2/umd/react.development.js)
Reacrt-DOM(https://cdn.bootcss.com/react-dom/16.10.2/umd/react-dom.development.js)
cjs和umd的区别: cjs全称CommonJS,是Node.js支持的模块规范,umd是统一模块定义,兼容各种模块规范(含浏览器)理论上优先使用umd,同时支持Node.js和浏览器,最新的模块规范是使用import和export关键字
webpack引入React
import...from...
yarn add react react-dom
import React from 'react'
import ReactDOM from 'react-dom'
crate-react-app
//创建项目,脚手架
yarn global add create-react-app
create-react-app react-demo-4
虚拟DOM(virtual Document Object Model)
DOM是浏览器中的概念,用JS对象来表示页面上的元素,并且提供了操作DOM对象的API
什么是React中的虚拟DOM:是框架里面的概念,用JS对象模拟页面上的DOM和DOM嵌套
为什么要实现虚拟DOM:为了实现页面中DOM元素的高效更新
总结:用JS对象的形式,来模拟页面上的DOM嵌套关系
JSX
X表示扩展,js的扩展。
使用babel-loader就可以,babel-loder被webpack内置了。
生产环境不推荐bootcdn引入,因为效率太低

React组件
react有类组件和函数组件两种
函数组件

类组件

标签会被翻译成什么
//在React中<div />或者<MyCompoent />会被翻译成什么?
//如果是字符串会创建一个元素(virtual dom),如果是函数会调用这个函数,获取返回值。
//如果传入一个类,则在类前面加一个new(这会导致执行constructor),获取一个组件对象,然后调用对象的render方法,获取返回值
我们可以根据babel online进行验证

props | state
外部数据(props)和内部数据(state)
class 组件使用props state
import React from 'react';
class Parent extends React.Component {
constructor() {
super()
this.state = { name: '小明' }
}
changeName = (newName) => {
console.log(this)
this.setState({ ...this.state, name: newName })//第二个参数是个callback
}
render() {
return (
<div>
父组件
<Son name={this.state.name} changeName={this.changeName} />
</div>
)
}
}
class Son extends React.Component {
render() {
console.log(this.props)
return (
<div>子组件
<p>父组件给我的名字是:{this.props.name}</p>
<button onClick={() => {
this.props.changeName('新名字')
}}>changeName</button>
</div>
)
}
}
类组件注意事项:
- this.state.n += 1 无效?
其实n已经改变了,只不过UI不会自动更新而已
调用setState才会触发UI更新(异步更新)
因为React没有像Vue监听data一样监听state
setState会异步更新UI,所以推荐使用setState(function)
class会自动合并state 的第一层,第二次不会合并,需要自己合并
setState(newState,callBack)//第二个参数在更新完state后进行回调。 React希望我们不要修改旧得state(不可变数据)
这是一种理念(函数式)
事件绑定

生命周期
//弃用钩子
componentWillReceiveProps(newProps,nextContent) 更名为UNSAFE_componentWillReceiveProps
当组件接受新的props时会触发此钩子
- constructor() -在这里初始化state
用途:初始化props,state,但此时不能调用setState,用来写bind this
- static getDerivedStateFromProps()
- shouldComponentUpdate() -return false阻止更新
用途:返回true表示不阻止ui更新,返回fasle表示阻止ui更新
class Parent extends React.Component {
constructor() {
super()
this.state = { n: 0 }
}
changeName = () => {
this.setState((state) => { return { ...state, n: state.n + 1 } })
this.setState((state) => {
return { ...state, n: state.n - 1 }
})
}
shouldComponentUpdate(newProps, newState) {
if (newState.n === this.state.n) {//如果n没有发生变化话 就不渲染
return false
} else {
return true
}
}
render() {
console.log('render了一次')
return (
<div>
父组件:{this.state.n}
<button onClick={this.changeName}>
+1
</button>
</div>
)
}
}
//我们也可以使用React.PureComponent,实现该功能,PureComponent 会在 render 之前对比新 state 和旧 state 的每一个 key,以及新 props 和旧 props 的每一个 key。
//如果所有 key 的值全都一样,就不会 render;如果有任何一个 key 的值不同,就会 render,但只会对比1层
- render()-创建虚拟DOM
用途:展示视图 <React.Fragment / >可以缩写<></> render里面可直接写for循环,需要用数组
- getSnapshotBeforeUpdate()
- componentDidMount()-组件已出现在页面
import React from 'react';
import './App.css';
class Parent extends React.Component {
divRef = undefined
constructor() {
super()
this.state = {
n:0
}
this.divRef = React.createRef()
}
componentDidMount() {
console.log('我已经挂载到了页面,现在你可以发请求或者可以获取到这个div的属性了')
const width = this.divRef.current.clientWidth
this.setState((state)=>{
return {...state,width}
})
}
render() {
console.log('render了一次')
return (
<div ref={this.divRef}>
父组件:{this.state.width}
</div>
)
}
}
- componentDidUpdate()-组件已更新

- static get DerivedStateFromError()
- componentDidCatch()

函数组件
函数组件替代class组件
-
函数组件没有state React推出hooks api ,useState可以解决
-
函数组件没有生命周期 React推出hooks api ,useEffect可以解决
函数组件使用props 和state
import React, { useState } from 'react';
function Parent() {
const [obj, setName] = useState({ name: '小明' })
return (
<div className="Parent">
我是父组件
<Son name={obj.name} changeName={setName} />
</div>
)
}
function Son(props) {
return (
<div className="Son">
我是子组件:父组件给我的值是:{props.name}
<button onClick={() => {
props.changeName((state) => {
return {
...state, name: '小黑'}
})
}}>改名字</button>
</div>
);
}
useEffect
模拟componentDidMount
useEffect(()=>{console.log('第一次渲染')},[])//写空数组可以模拟只在第一次调用
模拟componentDidUpdate
useEffect(()=>{console.log('任意属性变了')})
useEffect(()=>{console.log('n变了')},[n])
模拟componentWillUnmount
useEffect(()=>{
console.log('第一次渲染')
return ()=>{
console.log('组件要死了')
}
})
自定义hook
//模拟componentDidUpdate ,页面更新了执行回调
const [N, setN] = useState(0)//依赖n
//自定义Hook
const useX = (callback, dep) => {//接受一个,回调和依赖项
const [count, setCount] = useState(0)//用来计算渲染次数,排除第一次挂载页面
useEffect(() => {
setCount(x => x + 1)
}, [dep])//每次依赖发生变化,+1
useEffect(() => {//如果第二次渲染触发回调
if (count > 1) {
callback.call(null)
}
}, [count, callback])
}
useX(() => console.log('更新了'), N)//调用
Vue编程模型vs React的编程模型

vue在修改原本的数据,react返回新数据