再仔细读读react18官方文档吧 20220531

章节回顾:



代码分割

作用 / 优点

对你的应用进行代码分割能够帮助你“懒加载”当前用户所需要的内容,能够显著地提高你的应用性能。

尽管并没有减少应用整体的代码体积,但你可以避免加载用户永远不需要的代码,

并在初始加载的时候减少所需加载的代码量。

方法

在你的应用中引入代码分割的最佳方式是通过动态 import() 语法。

例如:

import("./math").then(math => {
  console.log(math.add(16, 26));
});

懒加载

React.lazy & Suspense

使用

import { Suspense, lazy } from 'react'
// 通过懒加载形式获取组件
// OtherComponent组件在文件中必须是export default OtherComponent形式导出的
const OtherComponent = lazy(() => import('./OtherComponent '))

不过,这样直接使用组件,在初始阶段会有一个加载空档期,

此时,react并不知道要做什么,所以需要用Suspense 包裹住懒加载的组件,

以此来告诉react在加载空档期要做什么。

Suspense是一个组件,标签中有一个fallback属性

fallback 属性接受任何在组件加载过程中你想展示的 React 元素。

比如空档期展示一个loading...文案。

完整使用方法

import { Suspense, lazy } from 'react'

const OtherComponent = lazy(() => import('./OtherComponent '))

const MyComponent = () => {
  return <div>
	<Suspense fallback={ <div>loading...</div> }>
	  <OtherComponent />
	</Suspense>
  </div>
}

使用React.lazy & Suspense 还可以进行路由懒加载

import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Switch>
        <Route exact path="/" component={Home}/>
        <Route path="/about" component={About}/>
      </Switch>
    </Suspense>
  </Router>
);

loadable-components

React.lazy & Suspense 不支持服务端渲染,

如果需要服务端渲染,可以使用loadable-components懒加载库。

git地址

https://github.com/gregberge/loadable-components

安装

npm install @loadable/component

使用

import loadable from '@loadable/component'

const OtherComponent = loadable(() => import('./OtherComponent'))

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  )
}

Context

先回顾一下React中的组件间通信方法:

父传子

父组件通过props向子组件传值

子传父

父组件通过props向子组件传递一个方法

子组件把要传的值作为参数调用该方法

父组件通过该方法传入的参数,获取到值

兄弟间

子传父,再父传子


如果父子层级较多,那么需要每层组件都要手动传递一次或多次props,才能拿到想要的值。

这就很离谱!!!


Context 就是用来解决这个问题的。

它提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。

它可以让数据在整个组件树之间“共享”

在Class组件中的使用方法

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<div id="root"></div>
	<!-- 开发模式下用development版本 -->
	<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
	<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
	<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
	<script type="text/babel">
		// 创建一个Context 并设定初始值"light"
		const Context = React.createContext('light')

		class Com1 extends React.Component {
			render() {
				return (
					// 使用Provider传递值,在Com1组件树中的所有组件都能直接使用传递的值
					// 设定传递的值value为"dark"
					// 注意,这里的属性必须是value
					<Context.Provider value="dark">
						<Com2 />
					</Context.Provider>
				)
			}
		}
		// 中间使用不到这个值的组件就不用管了
		class Com2 extends React.Component {
			render() {
				return <div>
					<Com3 />
				</div>
			}
		}
		
		class Com3 extends React.Component {
			// 指定contextType 读取传递的值context
			// this.context就是传递的值
			static contextType = Context
			render() {
				return <p>{this.context}</p>
			}
		}

		const wrap = document.querySelector('#root')
		const root = ReactDOM.createRoot(wrap)
		root.render(<Com1 />)
	</script>
</body>
</html>

在函数组件中使用useContext

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<div id="root"></div>
	<!-- 开发模式下用development版本 -->
	<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
	<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
	<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
	<script type="text/babel">
		const {useContext} = React
		// 创建一个Context 并设定初始值"light"
		const Context = React.createContext('light')

		const Com1 = () => {
			return (
				// 使用Provider传递值,在Com1组件树中的所有组件都能直接使用传递的值
				// 设定传递的值value为"dark"
				// 注意,这里的属性必须是value
				<Context.Provider value="dark">
					<Com2 />
				</Context.Provider>
			)
		}
		// 中间使用不到这个值的组件就不用管了
		const Com2 = () => {
			return <div>
				<Com3 />
			</div>
		}
		
		const Com3 = () => {
			// 哪个组件要使用传递的值,就在哪个组件中使用useContext来获取
			const context = useContext(Context)
			return <p>{context}</p>
		}

		const wrap = document.querySelector('#root')
		const root = ReactDOM.createRoot(wrap)
		root.render(<Com1 />)
	</script>
</body>
</html>

缺点

会导致组件复用性变差

错误边界(Error Boundaries)

什么是错误边界?

错误边界是一种 React 组件,这种组件可以捕获并打印发生在其子组件树任何位置的 JavaScript 错误,

并且,它会渲染出备用 UI,而不是渲染那些崩溃了的子组件树。

错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误。

错误边界解决了什么问题?

部分UI组件内的js代码出现错误,会导致页面崩溃,整个页面无法渲染。

错误边界就是捕获和打印这些错误,并在出现该问题时,渲染备用UI

PS:

对开发人员来说,它的作用就是快速定位错误问题的位置。

举个例子:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<div id="root"></div>
	<!-- 开发模式下用development版本 -->
	<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
	<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
	<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
	<script type="text/babel">
		const Child = () => {
			return <div>
				{haha}
			</div>
		}

		const App = () => {
			return <Child />
		}

		const wrap = document.querySelector('#root')
		const root = ReactDOM.createRoot(wrap)
		root.render(<App />)
	</script>
</body>
</html>

在示例的Child组件中,我不小心把字符串"haha"写成了变量haha

导致页面出现了问题,无法渲染。

现在,我给组件加上一个错误边界:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<div id="root"></div>
	<!-- 开发模式下用development版本 -->
	<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
	<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
	<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
	<script type="text/babel">
		class ErrorBoundary extends React.Component {
			constructor(props) {
				super(props)
				this.state = {
					hasError: false
				}
			}

			static getDerivedStateFromError(error) {
				// 更新 state 使下一次渲染能够显示降级后的 UI
				return { hasError: true }
			}

			componentDidCatch(err, errInfo) {
				console.log(err, errInfo)
			}

			render() {
				if(this.state.hasError) {
					return <h3>出错啦...</h3>
				}
				return this.props.children
			}
		}

		const Child = () => {
			return <div>
				{haha}
			</div>
		}

		const App = () => {
			return <ErrorBoundary>
				<Child />
			</ErrorBoundary>
		}

		const wrap = document.querySelector('#root')
		const root = ReactDOM.createRoot(wrap)
		root.render(<App />)
	</script>
</body>
</html>

错误边界组件ErrorBoundary中捕获到了错误并进行了定位:

ErrorBoundary

此时,js代码出现了错误,但是页面渲染了备用UI,

页面显示内容出错啦...

在这里插入图片描述


使用错误边界有哪些注意事项?

1. 错误边界组件必须是class组件

2. 错误边界仅可以捕获其子组件的错误,它无法捕获其自身的错误

3. 它仅用于开发环境,在生产环境必须将其禁用 。

4. 它无法捕获事件处理,因为React不需要它来捕获

5. 无法捕获异步代码中的错误

6. 无法捕获服务端渲染中的错误

提醒:

自 React 16 起,任何未被错误边界捕获的错误将会导致整个 React 组件树被卸载。

Fragment

Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。

先来看一个不使用Fragment的例子:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<div id="root"></div>
	<!-- 开发模式下用development版本 -->
	<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
	<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
	<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
	<script type="text/babel">

		const App = () => {
			return <div>
				<p>hello react !</p>
			</div>
		}

		const wrap = document.querySelector('#root')
		const root = ReactDOM.createRoot(wrap)
		root.render(<App />)
	</script>
</body>
</html>

页面渲染效果:

在这里插入图片描述

可以看到, 页面中多了一个无意义的div标签


使用Fragment:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<div id="root"></div>
	<!-- 开发模式下用development版本 -->
	<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
	<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
	<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
	<script type="text/babel">

		const App = () => {
			return <React.Fragment>
				<p>hello react !</p>
			</React.Fragment>
		}

		const wrap = document.querySelector('#root')
		const root = ReactDOM.createRoot(wrap)
		root.render(<App />)
	</script>
</body>
</html>

再看下页面渲染结果:

在这里插入图片描述

渲染正常,且没有无意义的div标签了。


它还有个短语法:

<></>

使用的时候一直报错,略过。


在当前版本中,React.Fragment仅支持key属性。

举例:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<div id="root"></div>
	<!-- 开发模式下用development版本 -->
	<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
	<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
	<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
	<script type="text/babel">

		const App = () => {
			return <div>
				{
					[1, 2, 3].map((item, index) => {
						return <React.Fragment key={index}>
							<p>hello, react {item}</p>
						</React.Fragment>
					})
				}	
			</div>
		}

		const wrap = document.querySelector('#root')
		const root = ReactDOM.createRoot(wrap)
		root.render(<App />)
	</script>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值