React系列文章导航
state = { count: 0 }
add = () => {
const { count } = this.state
this.setState({ count: count + 1 })
}
render() {
return (
<div>
<h1>当前和为{this.state.count}</h1>
<button onClick={this.add}>加1</button>
</div>
)
}
add = () => {
const { count } = this.state
// 该回调函数是调用完render()后再进行回调,因此该回调一般用来获取更新后的状态值
// this.setState({ count: count + 1 }, () => {
// console.log(this.state.count)
// })
this.setState(state => ({ count: state.count + 1 }))
}
看起来写法2和写法1没有什么区别,只不过写成了个箭头函数而已,但是希望大家知道,写法2的情况下,我还可以接收其他参数,比如父组件App
传入的参数,那么我在写法2中就可以这么写:
this.setState((state, props) => {
console.log(props)
return { count: state.count + 1 }
})
然后父类App
组件中随意传入一个参数:
此时点击页面的加1
按钮后:可以发现获取到了对应的props
值
写法1:
setState(stateChange, [callback])
------对象式的setState
。stateChange
为状态改变对象(该对象可以体现出状态的更改)。callback
是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用。写法2:
setState(updater, [callback])
------函数式的setState
。updater
为返回stateChange
对象的函数。updater
可以接收到state
和props
。callback
是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。lazyLoad
顾名思义,懒加载,一般在我们项目特别大的时候去使用它。用的最多的就是路由。案例如下:
import React, { Component } from 'react'
export default class About extends Component {
render() {
return (
<div>
<h2>我是About组件</h2>
</div>
)
}
}
Home
组件:
import React, { Component } from 'react'
export default class Home extends Component {
render() {
return (
<div>
<h2>我是Home组件</h2>
</div>
)
}
}
lazyLoad
组件:
import React, { Component, lazy, Suspense } from 'react'
import { Link, Route } from 'react-router-dom'
// import Home from './About'
// import About from './Home'
const Home = lazy(() => import('./Home'))
const About = lazy(() => import('./About'))
export default class App 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">
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Suspense fallback={<h1>Loading...</h1>}>
{/**注册路由 */}
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
</Suspense>
</div>
</div>
</div>
</div>
</div>
)
}
}
App
组件:
import React, { Component } from 'react';
import Demo from './components/2_lazyLoad'
class App extends Component {
render() {
return (
<div>
<Demo />
</div>
);
}
}
export default App;
入口文件index.jsx
:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import { BrowserRouter } from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
, document.getElementById('root'))
测试步骤如下:
1.运行项目,按F12,点击下图图标:
2.选择Fast3G:(降低页面加载速度,可以这么理解)
3.点击About
导航:
4.点击Home
导航:
可见有一个明显的加载过程,这里说个问题:
我们一般项目中引入组件的写法是:
import Home from './About'
但是这种写法,会导致页面初次加载的时候,就去将Home
组件给加载进来。
假设我们有一个非常大的页面,里面包含了1W个组件,那么我们在使用过程中,万一只需要用到其中1个组件,那根据上面的写法,岂不是白白的将剩下9999个组件都进行了渲染?岂不是很浪费页面的加载时间。
因此,我们需要按需加载,即懒加载,只有当组件需要用到的时候,我们再加载。
步骤:
const Home = lazy(() => import('./Home'))
< Suspense>
指定在加载得到路由打包文件前显示一个自定义loading界面,同时定义一个回调,例如:<Suspense fallback={<h1>loading.....</h1>}>
<Switch>
<Route path="/xxx" component={Xxxx}/>
<Redirect to="/login"/>
</Switch>
</Suspense>
Hook是React16.8.0中新增加的特性。可以让你再函数组件中使用state
以及其他的React特性。
有3个常用的Hook:
React.useState()
React.Effect()
React.useRef()
StateHook让函数组件也可以有state
状态,并进行状态数据的读写操作。
import React, { Component } from 'react'
// 类式组件
// export default class Demo extends Component {
// state = { count: 0 }
// add = () => {
// this.setState(state => ({ count: state.count + 1 }))
// }
// render() {
// return (
//
// 当前和为{this.state.count}
//
//
// )
// }
// }
// 函数式组件
function Demo() {
return (
<div>
<h1>当前和为{this.state.count}</h1>
<button onClick={this.add}>加1</button>
</div>
)
}
export default Demo
因为函数式组件,没有this
。 因此更改如下:
// 函数式组件
function Demo() {
// 此时获得的a对象是一个数组,useState中传入的参数代表初始值
const [count, setCount] = React.useState(0)
// 若有个变量为name,那么可以仿照该写法就是:
// const [name ,setName] = React.useState('tom')
function add() {
setCount(count + 1)
// 第二种写法
// setCount(count => count + 1)
}
return (
<div>
<h1>当前和为:{count}</h1>
<button onClick={add}>加1</button>
</div>
)
}
那么依旧可以有类式组件的效果,即更改state
值。
state
状态, 并进行状态数据的读写操作。const [xxx, setXxx] = React.useState(initValue)
useState()
说明:参数: 第一次初始化指定的值在内部作缓存
返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数
(4). setXxx()
2种写法:
setXxx(newValue):
参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
setXxx(value => newValue):
参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
EffectHook用来在函数组件中执行副作用操作。
场景:打开上述的求和案例页面,和能够实现自增长的加1,并且增加卸载按钮用来卸载组件。
那么类式组件写法:
class Demo extends Component {
state = { count: 0 }
add = () => {
this.setState(state => ({ count: state.count + 1 }))
}
componentDidMount() {
this.timer = setInterval(() => {
this.setState(state => ({ count: state.count + 1 }))
}, 1000);
}
// 卸载组件的时候,必须把相关的定时器给卸载了,否则控制台会输出报错信息。
unmount() {
ReactDOM.unmountComponentAtNode(document.getElementById('root'))
}
// 因此这里需要写componentWillUnmount,来负责定时器的关闭
componentWillUnmount() {
clearInterval(this.timer)
}
render() {
return (
<div>
<h1>当前和为{this.state.count}</h1>
<button onClick={this.add}>加1</button>
<button onClick={this.unmount}>卸载</button>
</div>
)
}
}
函数式组件写法:
function Demo() {
const [count, setCount] = React.useState(0)
function add() {
setCount(count + 1)
}
React.useEffect(() => {
let timer = setInterval(() => {
setCount(count => count + 1)
}, 1000)
return () => {
clearInterval(timer)
}
}, [])
function unmount() {
ReactDOM.unmountComponentAtNode(document.getElementById('root'))
}
return (
<div>
<h1>当前和为:{count}</h1>
<button onClick={add}>加1</button>
<button onClick={unmount}>卸载</button>
</div>
)
}
1.发ajax请求数据获取
2. 设置订阅 / 启动定时器
3. 手动更改真实DOM
useEffect(() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
}
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行
useEffectHook
看做如下三个函数的组合:
componentDidMount()
componentDidUpdate()
componentWillUnmount()
需求:输入框输入文本,点击显示数据按钮,弹框并展示相应内容。
类式组件写法:
class Demo extends Component {
myRef = React.createRef()
show = () => {
alert(this.myRef.current.value)
}
render() {
return (
<div>
<input type="text" ref={this.myRef} />
<button onClick={this.show}>展示数据</button>
</div>
)
}
}
函数式组件写法:(基本上一致,只需要注意不要加上this
即可)
function Demo() {
const myRef = React.useRef()
function show() {
alert(myRef.current.value)
}
return (
<div>
<input type="text" ref={myRef} />
<button onClick={show}>展示数据</button>
</div>
)
}