提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
Hook 是 React 16.8 的新增特性。
它可以让你在编写函数式组件时使用 state 以及其他的 React 特性。这里借用阮一峰老师的一句话 —— 钩子(hook)就是 React 函数组件的副效应解决方案,用来为函数组件引入副效应。 函数组件的主体只应该用来返回组件的 HTML 代码,所有的其他操作(副效应)都必须通过钩子引入。
React.useState()
React.useEffect()
React.useRef()
const [状态, 更改状态的方法] = React.useState(initValue)
import React from 'react'
export default function Plus() {
const [count,setCount] = React.useState(0)
function add() {
setCount(count+1) //写法一
// setCount((count) => {return count+1}) 写法二
}
return (
<>
<h1>当前求和为{count}</h1>
<button onClick={add}>点我加一</button>
</>
)
}
Plus函数调几次?
答:它和类组件的render
一样,调1+n
次
第4行也随Plus调用了1+n
次,为什么state最终不是0?
答:React底层在执行useState函数之后,把初始状态
保存起来了,
因此后面在调用useState初始状态0不会覆盖更改后的状态
const refContainer = useRef()
React.createRef()
一样import React from 'react'
export default function Plus() {
const myRef = React.useRef()
function show() {
alert(myRef.current.value)
}
return (
<>
<input type="text" ref={myRef}/>
<button onClick={show}>点我展示输入内容</button>
</>
)
}
useEffect()
是通用的副效应钩子 。找不到对应的钩子时,就可以用它。其实,从名字也可以看出来,它跟副效应(side effect)直接相关。生命周期钩子
React.useEffect(() => {
1.相当于 conponentDidMount()、conponentDidUpdate()
return ()=>{ 2.相当于conponentWillUnmount() }
},[3.监测哪个状态])
import React from 'react'
import ReactDOM from "react-dom"
export default function Plus() {
const [count, setCount] = React.useState(0)
React.useEffect(() => {
let timer = setInterval(() => {
setCount(count => count+1)
},1000)
return () => {
clearInterval(timer)
}
},[])
//卸载组件
function unMount() {
ReactDOM.unmountComponentAtNode(document.getElementById("root"))
}
return (
<>
<h1>当前求和为{count}</h1>
<button onClick={unMount}>卸载组件</button>
</>
)
}
useEffect传入的第一个值:这个函数,有可能相当于componentDidMount
、componentDidUpdate
、componentWillUnmount
(甚至有可能同时相当于componentDidMount和componentDidUpdate!
)
useEffect传入的第二个值:这个[ ],方括号里面是啥(state),它就监测啥(state)
useEffect里的参数:
①同时相当于componentDidMount/componentDidUpdate
:useEffect只传一个参数useEffect( ()=>{} ) ----------> 它等于谁都监测,组件一挂载和任何状态变动,都会回调那个作为参数的函数
②相当于componentDidMount
:useEffect( ()=>{} , [] ) ----------> 第二个参数,[ ]里什么都不写 --------> 相当于谁都不监测
③相当于componentWillUnmout
: useEffect( ()=>{ return ()=>{} } ) --------> 第一个参数的返回值的这个函数相当于componentWillUnmout
用的时候才加载,一般是路由组件进行懒加载
如果不用路由懒加载,页面在第一次进入的时候,就请求了所有组件的数据,如果组件过多,过多的请求这就没有必要了,应该是用户按哪个链接再请求哪个组件
import React, { Component, lazy, Suspense} from 'react'
import {NavLink,Route} from 'react-router-dom'
// import Home from './Home'
// import About from './About'
import Loading from './Loading'
const Home = lazy(()=> import('./Home') )
const About = lazy(()=> import('./About'))
export default class Demo extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
<NavLink className="list-group-item" to="/about">About</NavLink>
<NavLink className="list-group-item" to="/home">Home</NavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Suspense fallback={<Loading/>}>
{/* 注册路由 */}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</Suspense>
</div>
</div>
</div>
</div>
</div>
)
}
}
文档碎片
可以不用必须有一个真实的DOM根标签了
import React, { Component,Fragment } from 'react'
export default class Demo extends Component {
render() {
return (
<Fragment kye={1}>
<input type="text"/>
<input type="text"/>
</Fragment>
)
}
}
上下文
一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信
const XxxContext = React.createContext()
<xxxContext.Provider value={数据}>
子组件
</xxxContext.Provider>
static contextType = xxxContext // 声明接收context
this.context // 读取context中的value数据
第二种方式: 函数组件与类组件都可以
<xxxContext.Consumer>
{
value => ( // value就是context中的value数据
要显示的内容
)
}
</xxxContext.Consumer>
在应用开发中一般不用context, 一般都用它来封装react插件
import React, { Component } from 'react'
import './index.css'
//创建Context对象
const MyContext = React.createContext()
const { Provider, Consumer } = MyContext
export default class A extends Component {
state = {username:'tom',age:18}
render() {
const {username,age} = this.state
return (
<div className="parent">
<h3>我是A组件</h3>
<h4>我的用户名是:{username}</h4>
<Provider value={{username,age}}>
<B/>
</Provider>
</div>
)
}
}
class B extends Component {
render() {
return (
<div className="child">
<h3>我是B组件</h3>
<C/>
</div>
)
}
}
/* class C extends Component {
//声明接收context
static contextType = MyContext
render() {
const {username,age} = this.context
return (
我是C组件
我从A组件接收到的用户名:{username},年龄是{age}
)
}
} */
function C(){
return (
<div className="grand">
<h3>我是C组件</h3>
<h4>我从A组件接收到的用户名:
<Consumer>
{value => `${value.username},年龄是${value.age}`}
</Consumer>
</h4>
</div>
)
}
只有当组件的state或props数据发生改变时才重新render()
Component中的shouldComponentUpdate()总是返回true(阀门总是打开的)
比较新旧state或props数据, 如果有变化才返回true, 如果没有返回false
shouldComponentUpdate(nextProps,nextState){
// console.log(this.props,this.state); //目前的props和state
// console.log(nextProps,nextState); //接下要变化的目标props,目标state
return !this.state.carName === nextState.carName
}
PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true
注意
浅比较
, 如果只是数据对象内部数据变了, 返回falsePureComponent
来优化import React, { PureComponent } from 'react'
import './index.css'
export default class Parent extends PureComponent {
state = {carName:"奔驰c36",stus:['小张','小李','小王']}
addStu = ()=>{
const {stus} = this.state
this.setState({stus:['小刘',...stus]})
}
changeCar = ()=>{
this.setState({carName:'迈巴赫'})
render() {
console.log('Parent---render');
const {carName} = this.state
return (
<div className="parent">
<h3>我是Parent组件</h3>
{this.state.stus}
<span>我的车名字是:{carName}</span><br/>
<button onClick={this.changeCar}>点我换车</button>
<button onClick={this.addStu}>添加一个小刘</button>
<Child carName="奥拓"/>
</div>
)
}
}
class Child extends PureComponent {
render() {
console.log('Child---render');
return (
<div className="child">
<h3>我是Child组件</h3>
<span>我接到的车是:{this.props.carName}</span>
</div>
)
}
}
错误边界(Error boundary):用来捕获后代组件错误,同时将报错的组件替换渲染出备用页面
只能捕获后代组件生命周期产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件、定时器中产生的错误
getDerivedStateFromError配合componentDidCatch
// 生命周期函数,一旦后台组件报错,就会触发
static getDerivedStateFromError(error) {
console.log(error);
// 在render之前触发
// 返回新的state
return {
hasError: true,
};
}
componentDidCatch(error, info) {
// 统计页面的错误。发送请求发送到后台去
console.log(error, info);
}
import React, { Component } from 'react'
import Child from './Child'
export default class Parent extends Component {
state = {
hasError:'' // 用于标识子组件是否产生错误
}
//当Parent的子组件出现报错时候,会触发getDerivedStateFromError调用,并携带错误信息
static getDerivedStateFromError(error){
console.log('@@@',error);
return {hasError:error}
}
componentDidCatch(){
console.log('此处统计错误,反馈给服务器,用于通知编码人员进行bug的解决');
}
render() {
return (
<div>
<h2>我是Parent组件</h2>
{this.state.hasError ? <h2>当前网络不稳定,稍后再试</h2> : <Child/>}
</div>
)
}
}