目录
异步加载组件
Context
错误边界
Refs and the DOM
Fragments
高阶组件
使用 Fetch
高阶组件应用
严格模式
使用 PropTypes 进行类型检查
Optimizing
React.lazy
函数能让你像渲染常规组件一样处理动态引入(的组件)。
使用之前:
import OtherComponent from './OtherComponent';
使用之后:
const OtherComponent = React.lazy(() => import('./OtherComponent'));
看具体代码:
LazyMain.jsx
import React, { Component, Suspense } from 'react'
// import Other from './Other'
const Other = React.lazy(() => import('./Other'))
/**
* fallback: 属性接受任何在组件加载过程中的你要展示的内容(React元素)
* 可以将 Suspense 组件置于懒加载组件之上的任何位置。甚至可以用一个 Suspense 组件包裹多个懒加载组件。
*/
export default class LazyMain extends Component {
render() {
return (
loading... }>
Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
我们先看看正常三个组件传递参数是怎样的:
Theme1Main.jsx
import React, { Component } from 'react'
import ToolBar from './ToolBar'
export default class Theme1Main extends Component {
constructor(props){
super(props)
this.state ={
msg:"Theme1Main_msg_data"
}
}
render() {
return (
)
}
}
ToolBar.jsx
import React, { Component } from 'react'
import LastChild from './LastChild'
export default class ToolBar extends Component {
render() {
return (
)
}
}
LastChild.jsx
import React, { Component } from 'react'
export default class LastChild extends Component {
render() {
return (
LastChild
{this.props.msg}
)
}
}
使用 context, 我们可以避免通过中间元素传递 props:
Theme2Main.jsx
import React, { Component } from 'react'
import Toolbar from './Toolbar'
/**
* Provider:提供者
* Consumer:接受者
* React.createContext("默认数据"):创建Context
* 尽可能避免使用,组件的复用性变得很差
*/
export const { Provider, Consumer } = React.createContext('default_data')
export default class Theme2Main extends Component {
render() {
return (
)
}
}
Toolbar.jsx
import React, { Component } from 'react'
import LastChild from './LastChild'
export default class Toolbar extends Component {
render() {
return (
)
}
}
LastChild.jsx
import React, { Component } from 'react'
import { Consumer } from './Theme2Main'
export default class LastChild extends Component {
render() {
return (
LastChild
{
value => {
return {value}
}
}
)
}
}
错误边界是一种 React 组件,这种组件可以捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误,同时展示降级 UI,而并不会渲染那些发生崩溃的子组件树。
如果一个 class 组件中定义了 static getDerivedStateFromError() 或 componentDidCatch() 这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。当抛出错误后,使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。
ErrorMain.jsx
import React, { Component } from 'react'
import ErrorBoundary from './ErrorBoundary'
import List from './List'
export default class ErrorMain extends Component {
render() {
return (
)
}
}
ErrorBoundary.jsx
import React, { Component } from 'react'
export default class ErrorBoundary extends Component {
constructor(props) {
super(props)
this.state = {
hasError: false
}
}
static getDerivedStateFromError(error) {
// 更新State 使下一次渲染能够显示降级后的UI
return {
hasError: true
}
}
componentDidCatch(error, errorInfo) {
// 发送错误,将错误信息发送给后台
console.log(error, errorInfo)
}
render() {
if (this.state.hasError) {
// 发生错误:降级显示新的UI
return 发生了错误!!!
}
// 组件组合
return this.props.children
}
}
List.jsx
import React, { Component } from 'react'
export default class List extends Component {
constructor(props) {
super(props)
this.state = {
list: ['tom', 'jack']
}
}
render() {
return (
{
this.state.list.map((ele, index) => {
return - {ele}
})
}
)
}
}
注意:错误边界仅可以捕获其子组件的错误,它无法捕获其自身的错误。如果一个错误边界无法渲染错误信息,则错误会冒泡至最近的上层错误边界,这也类似于 JavaScript 中 catch {}
的工作机制。
Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。
Refs 是使用 React.createRef()
创建的,并通过 ref
属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。
当 ref 被传递给 render
中的元素时,对该节点的引用可以在 ref 的 current
属性中被访问
不能在函数组件上使用 ref
属性,因为他们没有实例
RefsMain.jsx
import React, { Component } from 'react'
export default class RefsMain extends Component {
constructor(props){
super(props)
this.text = React.createRef()
}
componentDidMount(){
//Dom渲染完成
this.text.current.innerHTML = 'change after data'
}
render() {
return (
文本信息
)
}
}
React 中的一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。
FragmentMain.jsx
import React, { Component } from 'react'
/**
* React.Fragment:实现容器功能,单不会渲染成节点
*/
export default class FragmentMain extends Component {
constructor() {
super();
this.state = {
hasFlag: true
}
}
render() {
return (
Fragment
{
this.state.hasFlag ?
内容1
内容2
内容3
内容4
:
// 简写
<>
内容5
内容6
内容7
内容8
>
}
)
}
}
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
具体而言,高阶组件是参数为组件,返回值为新组件的函数。高阶组件是将组件转换为另一个组件
HigherMain.jsx
import React, { Component } from 'react'
/**
* 高阶组件
* 1. 函数
* 2. 参数是一个组件
* 3. 返回值也是一个组件
* 高阶组件的作用:提取可复用的部分,增加可复用性
*/
const withFetch =(ComposeComponent)=>{//ComposeComponent 'C'必须大写
return class extends React.Component{
componentDidMount(){
console.log('hello')
}
render(){
return
}
}
}
class MyData extends React.Component{
render(){
return (
MyData:{this.props.data}
)
}
}
const WithFetch =withFetch(MyData)
export default class HigherMain extends Component {
render() {
return (
)
}
}
fetch('http://example.com/movies.json')
.then(response => response.json())
.then(data => console.log(data));
这里我们通过网络获取一个 JSON 文件并将其打印到控制台。最简单的用法是只提供一个参数用来指明想 fetch()
到的资源路径,然后返回一个包含响应结果的 promise(一个 Response 对象)。
当然它只是一个 HTTP 响应,而不是真的 JSON。为了获取 JSON 的内容,我们需要使用 json() 方法(该方法返回一个将响应 body 解析成 JSON 的 promise)。
// Example POST method implementation:
async function postData(url = '', data = {}) {
// Default options are marked with *
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
return response.json(); // parses JSON response into native JavaScript objects
}
postData('https://example.com/answer', { answer: 42 })
.then(data => {
console.log(data); // JSON data parsed by `data.json()` call
});
News.jsx
import React, { Component } from 'react'
export default class News extends Component {
constructor(props) {
super(props);
this.state = {
movement: []
}
}
componentDidMount() {
fetch('http://iwenwiki.com/api/blueberrypai/getIndexMovement.php')
.then(res => res.json())
.then(data => {
console.log(data)
this.setState({
movement: data.movement
})
})
}
render() {
return (
新闻渲染
{
this.state.movement.map((ele, index) => {
return - {ele.content}
})
}
)
}
}
Banner.jsx
import React from 'react'
import withFetch from './withFetch'
const Banner = withFetch('http://iwenwiki.com/api/blueberrypai/getIndexMovement.php')(props => {
return (
高阶组件应用
{
props.data.movement.map((ele, index) => {
return - {ele.content}
})
}
)
}
)
export default Banner
withFetch.jsx
import React from 'react'
const withFetch = (url) => (View) => {
return class extends React.Component {
constructor(props) {
super(props)
this.state = {
data: null,
loadding: true,
}
}
componentDidMount() {
fetch(url).then(res => res.json())
.then(data => {
this.setState({
loadding: false,
data
})
})
}
render() {
if (this.state.loadding) {
return (
loading......
)
}else{
return
}
}
}
}
export default withFetch
StrictMode
是一个用来突出显示应用程序中潜在问题的工具。与 Fragment
一样,StrictMode
不会渲染任何可见的 UI。它为其后代元素触发额外的检查和警告。
1. 识别不安全的生命周期
2. 关于使用过时字符串 ref API 的警告
3. 关于使用废弃的 findDOMNode 方法的警告
4. 检测意外的副作用
5. 检测过时的 context API
StrictMode严格模式只有在开发环境下生效,在生产模式下无效
StrictModeMain.jsx
import React, { Component } from 'react'
import ErrorAble from './ErrorAble'
export default class StrictModeMain extends Component {
render() {
return (
严格模式
)
}
}
ErrorAble.jsx
import React, { Component } from 'react'
export default class ErrorAble extends Component {
/**
* 过时的
*/
componentWillMount() {
console.log("DOM渲染之前");
}
componentDidMount() {
console.log("DOM渲染之后");
}
render() {
return (
测试严格模式
)
}
}
随着应用程序不断增长,可以通过类型检查捕获大量错误。PropTypes
提供一系列验证器,可用于确保组件接收到的数据类型是有效的
当传入的 prop
值类型不正确时,JavaScript 控制台将会显示警告。出于性能方面的考虑,propTypes
仅在开发模式下进行检查。
propTypes
类型检查发生在 defaultProps
赋值后,所以类型检查也适用于 defaultProps
。
PropMain.jsx
import React, { Component } from 'react'
import Greeting from './Greeting'
export default class PropMain extends Component {
render() {
return (
Props类型验证
)
}
}
Greeting.jsx
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class Greeting extends Component {
render() {
return (
{this.props.title}
{this.props.age}
)
}
}
// 类型验证
Greeting.propTypes = {
title:PropTypes.string,
age:PropTypes.number
}
// 默认值
Greeting.defaultProps ={
age:0
}
// typeScript:js高集,增加了静态类型检查
// Flow
OptimizingMain.jsx
import React, { Component } from 'react'
import Child1 from './Child1'
import Child2 from './Child2'
export default class OptimizingMain extends Component {
constructor(props) {
super(props);
this.state = {
message: "消息提示",
count: 0
}
}
incrementHandle = () => {
this.setState({
count: this.state.count + 1
})
}
render() {
console.log("主文件 ---> render");
return (
性能优化
{this.state.count}
)
}
}
Child1.jsx
import React, { Component } from 'react'
export default class Child1 extends Component {
render() {
console.log("child1 ---> render");
return (
Child1
{ this.props.message }
)
}
}
Child2.jsx
import React, { Component } from 'react'
export default class Child2 extends Component {
render() {
console.log("Child2 ---> render");
return (
Child2
{this.props.message}
)
}
}
从上面的代码和视图可以看到,只要父组件加载或更新了,其子组件也会加载,那如何优化呢?
1.PureComponent
PureComponent:对数据进行浅比较
Component:不会对数据进行比较
2.shouldComponentUpdate
Child2.jsx
import React, { Component } from 'react'
export default class Child2 extends React.PureComponent {
render() {
console.log("Child2 ---> render");
return (
Child2
{this.props.message}
)
}
}
Child1.jsx
import React, { Component } from 'react'
export default class Child1 extends Component {
/**
* 优化
*/
shouldComponentUpdate(nextProps,nextState){
if(nextProps.message === this.props.message){
return false;
}
return true;
}
render() {
console.log("child1 ---> render");
return (
Child1
{ this.props.message }
)
}
}
对于组件来说,很多时候,我们需要做性能优化:
1. 定时器:在组件销毁时,需要取消
2. 网络请求:在组件销毁时,取消网络请求
3. 事件监听:在组件销毁时,需要销毁事件处理函数
Optimizing2Math.jsx
import React, { Component } from 'react'
const MyAPI = {
count: 0,
subScribe(cb) {
this.intervarId = setInterval(() => {
this.count += 1
cb(this.count)
}, 1000)
},
unSubScribe() {
clearInterval(this.intervarId);
this.reset();
},
reset() {
this.count = 0;
}
}
export default class Optimizing2Math extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
componentDidMount() {
MyAPI.subScribe(currentCount => {
this.setState({
count: currentCount
})
})
}
componentWillUnmount() {
// 组件销毁之前,先清除定时器
MyAPI.unSubScribe();
}
render() {
return (
性能优化2
{this.state.count}
)
}
}
React高级先到这里,接下来更新的是网络请求部分的基础知识......