使用creat-react-app创建项目
which npx//查看npx是否已安装npx creat-react-app myproject//创建项目
用eject结构编译脚本
npm run eject
react最新特性简介及context的使用
- Context
- ContextType
- lazy
- Suspense
- memo
- context提供了一种数据传递方式,可以在组件树之间传递,而不必一级一级手动传递
context工作原理:有一个context实例对象,派生出
Provider和Consumer两个组件。
- 单个context的使用 app.js文件中引入context
import { Component, createContext } from 'react'
const BatteryContext = createContext()
class Middle extends Component {
render(){
return <Leaf />
}
}
class Leaf extends Component {
render(){
return (<BatteryContext.Consumer>
{
battery => <h1>Battery: {battery}</h1>
}
</BatteryContext.Consumer>)
}
}
class App extends Component {
state = {
battery: 60
}
minusBattery = () => {
this.setState({
battery: this.state.battery-1
})
}
render(){
const { battery } = this.state
return (
<BatteryContext.Provider value={battery}>
<button type="button" onClick={this.minusBattery}>--</button>
<Middle></Middle>
</BatteryContext.Provider>
);
}
}
export default App;
- 多个context的使用 app.js文件中引入context
import logo from './logo.svg';
import './App.css';
import { Component, createContext } from 'react'
const BatteryContext = createContext()
const OnlineContext = createContext()
class Middle extends Component {
render() {
return <Leaf />
}
}
class Leaf extends Component {
render() {
return (<BatteryContext.Consumer>
{
battery => (
<OnlineContext.Consumer>
{
online => <h1>battery: {battery} online: {String(online)}</h1>
}
</OnlineContext.Consumer>
)
}
</BatteryContext.Consumer>)
}
}
class App extends Component {
state = {
battery: 60,
online: false
}
minusBattery = () => {
this.setState({
battery: this.state.battery - 1
})
}
reverseState = () => {
this.setState({
online: !this.state.online
})
}
render() {
const { battery, online } = this.state
return (
<BatteryContext.Provider value={battery}>
<OnlineContext.Provider value={online}>
<button type="button" onClick={this.minusBattery}>press --</button>
<button type="button" onClick={this.reverseState}>reverse state</button>
<Middle></Middle>
</OnlineContext.Provider>
</BatteryContext.Provider>
);
}
}
export default App;
- 假设我们想要在jsx结构之前获得battery的值呢?这时候就需要使用contextype了 这时候cousumer也可以去掉了,更方便
class Leaf extends Component {
static contextType = BatteryContext
render() {
const battery = this.context
return (
<h1>battery: {battery}</h1>
)
}
}
lazy和Suspense的使用
webpack的import语法,把文件打包成一个独立的模块,只有用到的时候才去加载,那么react组件是如何加载的呢 lazy函数:封装的是组件的导入行为,而不是组件
import React, { Component, lazy, Suspense } from 'react'
const About = lazy(() => import('./about.jsx')) //lazy返回就是一个react组件
class MyLazy extends Component {
render() {
return (
<div>
<Suspense fallback={<div>loading</div>}>
<About></About>
</Suspense>
</div>
)
}
}
export default MyLazy;
memo的使用
- 第一种情况:数据只有一个层级 点击按钮,组件mymemo也会跟着不断的重新render,可以通过shouldComponentUpdate 父组件app中的count变化,重新渲染子组件mymemo,这种情况可以通过shouldComponentUpdate,判断父组件传给子组件的数据有没有发生变化来确定是否重新渲染
mymemo.jsx文件:
import React, { Component } from 'react'
class MyMemo extends Component {
shouldComponentUpdate(nextProps, nextState){
if (nextProps.name === this.props.name) {
return false
}
return true
}
render() {
console.log('memo');
return (
<div>memo</div>
)
}
}
export default MyMemo;
app.jsx文件:
import './App.css';
import React, { Component } from 'react'
import MyMemo from './components/myMemo';
class App extends Component {
state = {
count: 0
}
addCount = () => {
this.setState({
count: this.state.count++
})
}
render() {
return (
<div>
<button onClick={this.addCount} >加1</button>
<MyMemo name="should memo reRender"></MyMemo>
</div>
);
}
}
export default App;
- 第二种情况:数据有多个层级 使用PureComponent,组件继承PureComponent,不需要使用shouldComponentUpdate, shouldComponentUpdate已经帮我们实现了shouldComponentUpdate的判断逻辑,但是也只是第一层级的数据 app.jsx文件:
import './App.css';
import React, { Component } from 'react'
import MyMemo from './components/myMemo';
class App extends Component {
state = {
count: 0
}
addCount = () => {
this.setState({
count: this.state.count++
})
}
render() {
return (
<div>
<button onClick={this.addCount} >加1</button>
<MyMemo name="should memo reRender"></MyMemo>
</div>
);
}
}
export default App;
mymemo.jsx文件:
import React, { Component, PureComponent } from 'react'
class MyMemo extends PureComponent {
render() {
console.log('memo');
return (
<div>memo</div>
)
}
}
export default MyMemo;
注意:以下代码展示了使用PureComponent需要注意的事项,它只关心父组件传给子组件的第一层级的数据是否发生变化,如果传多层级数据,比如对象,哪怕对象里面的某个属性发生变化,子组件也不会更新。 mymemo.jsx文件:
import React, { Component, PureComponent } from 'react'
class MyMemo extends PureComponent {
render() {
console.log('子组件是否重新渲染');
return (
<div>{this.props.person.age}</div>
)
}
}
export default MyMemo;
app.jsx文件:
import './App.css';
import React, { Component } from 'react'
import MyMemo from './components/myMemo';
class App extends Component {
state = {
count: 0,
person: {
age: 18
}
}
render() {
const person = this.state.person
console.log('父组件是否重新渲染');
return (
<div>
<button onClick={() => {
person.age++
this.setState({
person
})
}} >Add</button>
<MyMemo person={person}></MyMemo>
</div>
);
}
}
export default App;
3、第三种情况:使用PureComponent,虽然没给子组件传任何数据,传了一个内联的回调函数,也会引起子组件重新渲染 mymemo.jsx文件:
import './App.css';
import React, { Component } from 'react'
import MyMemo from './components/myMemo';
class App extends Component {
state = {
count: 0,
person: {
age: 18
}
}
render() {
const person = this.state.person
console.log('父组件是否重新渲染');
return (
<div>
<button onClick={() => {
person.age++
this.setState({
count: this.state.count+1
})
}} >Add</button>
<MyMemo person={person} cb={() => {}}></MyMemo>
</div>
);
}
}
export default App;
app.jsx文件:
import './App.css';
import React, { Component } from 'react'
import MyMemo from './components/myMemo';
class App extends Component {
state = {
count: 0,
person: {
age: 18
}
}
render() {
const person = this.state.person
console.log('父组件是否重新渲染');
return (
<div>
<button onClick={() => {
person.age++
this.setState({
count: this.state.count+1
})
}} >Add</button>
<MyMemo person={person} cb={() => {}}></MyMemo>
</div>
);
}
}
export default App;
优化上述代码,使得传入内联函数,却不会引起子组件重新渲染。把cb改写成箭头函数。mymemo.jsx文件的代码跟上面一样 app.jsx文件:
class App extends Component {
state = {
count: 0,
person: {
age: 18
}
}
callback = () => {
}
render() {
const person = this.state.person
console.log('父组件是否重新渲染');
return (
<div>
<button onClick={() => {
person.age++
this.setState({
count: this.state.count+1
})
}} >Add</button>
<MyMemo person={person} cb={this.callback}></MyMemo>
</div>
);
}
}
export default App;