React拓展 - setState
setState更新状态的两种写法
1、setState({}, [callback])
export default class Test extends Component {
state = {count: 0}
add = () => {
const { count } = this.state
this.setState({ count: 8 })
console.log(this.state.count) // 0 因为setState是异步的,所以会先执行这个
// 如果想要在setState操作后,拿state里的值进行操作,需要使用第二个回调函数或async await实现
this.setState({ count: 8 }, () => {
console.log(this.state.count) // 8
})
}
}
2、setState(updater, [callback])
export default class Test extends Component {
state = {count: 0}
add = () => {
// 通过函数式,可以获取到state和props
this.setState((state, props) => {
console.log(state, props)
return { count: state.count + 1 }
}, () => {
console.log(this.state.count) // 1
})
}
}
React拓展 - lazyLoad
路由懒加载
import {Component, lazy, Suspense} from "react"
// 懒加载路由模块
const Home = lazy(() => import("./Home/index"))
const About = lazy(() => import("./About/index"))
export default class Test extends Component {
render() {
return (
<div>
{/* Suspense 用于网络不好的时候,显示一个loading加载 */}
<Suspense fallback={<h1>Loading...</h1>}>
<Route path="/home" component={Home}>
<Route path="/about" component={About}>
</Suspense>
</div>
)
}
}
React拓展 - State Hook
State Hook 为了让使用者在函数式组件里使用state
import React from 'react';
export default function Test2() {
// React.useState() 用于初始化一个值,返回一个数组
// 数组第一个值为初始化的值
// 第二值为一个函数,用于修改第一个值
const [count, setCount] = React.useState(0);
const [name, setName] = React.useState('杜恒');
// 点击事件的回调
const changeCount = () => setCount(count + 1);
const changeName = () => setName('帅气的杜恒');
return (
<div>
<h2>当前值为:{count}</h2>
<button onClick={changeCount}>+ 1</button>
<hr />
<h2>当前名为:{name}</h2>
<button onClick={changeName}>改名</button>
</div>
);
}
React拓展 - Effect Hook
Effect Hook 为了让使用者在函数式组件里使用生命周期钩子
import React from 'react';
export default function Test2() {
const [count, setCount] = React.useState(0);
// React.useEffect 接收两个参数
// 第一个参数为函数,这个函数可以用作2个生命周期
// componentDidMount 或 componentDidUpdate
// 第二个参数为数组,这个数组用于监听state里的值
// 如果为空数组,则第一个参数当componentDidMount使用(只调用一次)
// 如果第二个参数没写或数组有值,则第一个参数当componentDidUpdate使用
React.useEffect(() => {
let timer = setInterval(() => {
setCount(count => count + 1);
}, 1000);
// 当return函数出去时,这个return出去的函数就可以当componentWillUnmount使用
return () => {
clearInterval(timer);
};
}, []);
return (
<div>
<h2>当前值为:{count}</h2>
</div>
);
}
React拓展 - Ref Hook
Ref Hook 和类式组件里面的createRef一样
import React from 'react';
export default function Test2() {
const inputRef = React.useRef();
const show = () => console.log(inputRef);
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={show}>点击提示</button>
</div>
);
}
React拓展 - Fragment
用于多个标签时包裹使用
import React, {Fragment} from 'react';
export default function Test2() {
return (
<Fragment>
<input type="text" />
<input type="text" />
</Fragment>
);
}
上面的写法可以写成下面的,直接使用空标签
import React, {Fragment} from 'react';
export default function Test2() {
return (
<>
<input type="text" />
<input type="text" />
</>
);
}
React拓展 - Context
Context 用于祖组件向后台组件通信
import React, { Component } from 'react';
// 1. 创建TestContext容器
const TestContext = React.createContext();
export default class A extends Component {
state = { name: '杜恒' };
render() {
return (
<div style={{ background: 'orange', padding: 10 }}>
我是A组件
{/* 2. 通过 Provider 将所有的state传入到后代组件里 */}
<TestContext.Provider value={this.state}>
<B />
</TestContext.Provider>
</div>
);
}
}
class B extends Component {
render() {
return (
<div>
我是B组件
<C />
</div>
);
}
}
// 第一种方式
class C extends Component {
/* 3. 申明使用context */
static contextType = TestContext;
render() {
console.log(this.context); // {name: "杜恒"}
return <div>我是C组件</div>;
}
}
// 第二种方式
function C() {
return (
<div>
<TestContext.Consumer>
{ value => console.log(value) }
</TestContext.Consumer>
</div>
)
}
React拓展 - 组件优化
组件有以下2个问题
- 组件内执行了setState,即使不改变状态数据,也会触发render更新
- 父组件render发生更新,会导致子组件的render也会触发
由于render受shouldComponentUpdate的阀门控制,因此需要在shouldComponentUpdate钩子里进行操作
import { Component } from 'react';
export default class A extends Component {
state = { count: 0 };
/* 赋值一个空对象,并没有改变state的值,也会触发更新 */
add = () => this.setState({});
/* 通过控制shouldComponentUpdate的返回值,控制是否触发render */
shouldComponentUpdate(nextProps, nextState) {
console.log(nextProps, nextState);
return !this.state.count === nextState.count;
}
render() {
console.log('render函数被触发了');
return <button onClick={this.add}>{this.state.count}</button>;
}
}
import { PureComponent } from 'react';
export default class A extends PureComponent {
state = { count: 0 };
add = () => this.setState({});
render() {
console.log('render函数被触发了');
return <button onClick={this.add}>{this.state.count}</button>;
}
}
React拓展 - Render Props
import { PureComponent } from 'react';
export default class A extends PureComponent {
render() {
return (
<div>
<h3>我是A组件</h3>
<B render={name => <C name={name} />}></B>
</div>
);
}
}
class B extends PureComponent {
state = { name: '杜恒' };
render() {
return (
<div>
<h3>我是B组件</h3>
{/* 类似插槽的功能 */}
{this.props.render(this.state.name)}
</div>
);
}
}
class C extends PureComponent {
render() {
console.log(this.props);
return <div>我是C组件</div>;
}
}
错误边界
错误边界用于当子组件出错时,控制错误范围在父组件,不会影响到其他的组件。错误边界只能在生产环境使用,开发环境会一闪而过
import { PureComponent } from 'react';
export default class A extends PureComponent {
/* 父组件定义一个状态,用于判断是否出错 */
state = {hasError: ''};
/* 当后代组件生命周期里有错误时,会触发该函数 */
static getDerivedStateFromError(error) {
return { hasError: error };
}
/* 这里可以抓捕到错误后,将错误发送给服务器,服务器在通知到钉钉等 */
componentDidCatch() {
console.log('组件发生错误!')
}
render() {
return (
<div>
<h3>我是A组件</h3>
{/* 动态渲染组件 */}
{this.state.hasError ? <h2>子组件出错</h2> : <B />}
</div>
);
}
}
class B extends PureComponent {
state = { name: '杜恒' };
render() {
return (
<div>
<h3>我是B组件</h3>
{this.state.name.map(() => (
<span>666</span>
))}
</div>
);
}
}
评论 (0)