We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
最新 React 版本为 v16.11.0,由于 16 版本的 React 的有巨大的改变更新,此篇文章做总结性的纪录。
v16.11.0
React Fiber 将应用同步 diff 更新改变为异步渲染更新。
由于异步更新会造成比较阶段阶段可能被打断,render阶段之前的生命周期方法可能引发多次执行,生命周期进行了较大调整。
render
React v16.3 之前的的生命周期函数 示意图:
再看看 16.3 的示意图:
Suspense 要解决的两个问题:
代码分片,对你的应用进行代码分割能够帮助你“懒加载”当前用户所需要的内容,能够显著地提高你的应用性能。
实际用例 Suspense + React.lazy
import React from 'react'; import moment from 'moment'; const Clock = () => { <h1>{moment().format('YYYY-MM-DD HH:mm:ss')}</h1>; }; export default Clock;
const OtherComponent = React.lazy(() => import('./Clock')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> </div> ); }
此代码将会在组件首次渲染时,自动导入包含 OtherComponent 组件的包。
React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 defalut export 的 React 组件。
然后应在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)。
原理:如果渲染组件失败会抛出错误,在外层Suspense捕获错误,得到的错误是动态导入组件的Promise类型错误时,会在resolve执行导入成功后重新 reRender。
Suspense
Promise
resolve
reRender
<Suspense>{show ? <OtherComponent /> : null}</Suspense>; class Suspense extends React.Component { static getDerivedStateFromError(error) { if (isPromise(error)) { error.then(reRender); } } }
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
为什么需要 Hook?
改革方向
使用数组解构的方式组合操控 state
import React, { useState } from 'react'; function Example() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); }
数组解构内部做了什么?
var countControl = useState('0'); // 返回一个有两个元素的数组 var initCount = countControl[0]; // 数组里的第一个值 var setNewCount = countControl[1]; // 数组里的第二个值
总结:省去了绑定事件的必须过程,不纠结 this 指向问题,复用代码
注意事项: Hooks,千万不要在 if 语句或者 for 循环语句中使用!
副作用:在 React 组件中执行过数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。
useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。
很多情况下,我们希望在组件加载和更新时执行同样的操作
class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0, }; } componentDidMount() { document.title = `You clicked ${this.state.count} times`; } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; } render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button> </div> ); } }
使用 useEffect 重构
import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); }
useEffect 将书写的代码逻辑做了改变:由关心生命周期的逻辑,变成了 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。
Effect只需要 componentDidMount
componentDidMount
useEffect(() => { document.title = `You clicked ${count} times`; }, []);
Effect只需要 componentDidUpdate
componentDidUpdate
只需要更新后执行,这种场景应该很少吧,方法很丑,不用,不用。
const mounted = useRef(); useEffect(() => { if (!mounted.current) { mounted.current = true; } else { // 这里只在update是执行 } });
Effect卸载阶段
使用 Effect return 一个函数调用表示组件即将卸载阶段的调用,模拟 componentWillUnmount
componentWillUnmount
function FriendStatus(props) { // ... useEffect(() => { // ... ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; });
Effect更新阶段性能优化(简单版)
在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。在 class 组件中,我们可以通过在 componentDidUpdate 中添加对 prevProps 或 prevState 的比较逻辑解决:
componentDidUpdate(prevProps, prevState) { if (prevState.count !== this.state.count) { document.title = `You clicked ${this.state.count} times`; } }
使用 useEffect,如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可:
useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // 仅在 count 更改时更新
Effect更新阶段性能优化(复杂版),模拟shouldComponentUpdate
shouldComponentUpdate
const areEqual = (prevProps, nextProps) => { // 返回结果和shouldComponentUpdate正好相反 // 访问不了state }; React.memo(Foo, areEqual);
import React, { useState, useCallback } from 'react'; function useBind(init) { let [value, setValue] = useState(init); let onChange = useCallback(function(event) { setValue(event.currentTarget.value); }, []); return { value, onChange, }; } function Page1(props) { let value = useBind(''); return <input {...value} />; }
const useHackerNewsApi = () => { const [data, setData] = useState({ hits: [] }); const [url, setUrl] = useState( 'https://hn.algolia.com/api/v1/search?query=redux', ); const [isLoading, setIsLoading] = useState(false); const [isError, setIsError] = useState(false); useEffect(() => { const fetchData = async () => { setIsError(false); setIsLoading(true); try { const result = await axios(url); setData(result.data); } catch (error) { setIsError(true); } setIsLoading(false); }; fetchData(); }, [url]); return [{ data, isLoading, isError }, setUrl]; };
function App() { const [query, setQuery] = useState('redux'); const [{ data, isLoading, isError }, doFetch] = useHackerNewsApi(); return ( <Fragment> <form onSubmit={event => { doFetch(`http://hn.algolia.com/api/v1/search?query=${query}`); event.preventDefault(); }} > <input type="text" value={query} onChange={event => setQuery(event.target.value)} /> <button type="submit">Search</button> </form> ... </Fragment> ); }
生命周期方法要如何对应到 Hook?
我该如何使用 Hook 进行数据获取?
该 demo 会帮助你开始理解。欲了解更多,请查阅 此文章 来了解如何使用 Hook 进行数据获取。
Hook
Suspense 异步获取 的进展
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
最新 React 版本为
v16.11.0
,由于 16 版本的 React 的有巨大的改变更新,此篇文章做总结性的纪录。概述
Fiber
React Fiber 将应用同步 diff 更新改变为异步渲染更新。
由于异步更新会造成比较阶段阶段可能被打断,
render
阶段之前的生命周期方法可能引发多次执行,生命周期进行了较大调整。React v16.3 之前的的生命周期函数 示意图:
再看看 16.3 的示意图:
Suspense
Suspense 要解决的两个问题:
代码分片,对你的应用进行代码分割能够帮助你“懒加载”当前用户所需要的内容,能够显著地提高你的应用性能。
实际用例 Suspense + React.lazy
此代码将会在组件首次渲染时,自动导入包含 OtherComponent 组件的包。
React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 defalut export 的 React 组件。
然后应在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)。
原理:如果渲染组件失败会抛出错误,在外层
Suspense
捕获错误,得到的错误是动态导入组件的Promise
类型错误时,会在resolve
执行导入成功后重新reRender
。Hook
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
为什么需要 Hook?
改革方向
useState
使用数组解构的方式组合操控 state
数组解构内部做了什么?
总结:省去了绑定事件的必须过程,不纠结 this 指向问题,复用代码
注意事项: Hooks,千万不要在 if 语句或者 for 循环语句中使用!
useEffect
副作用:在 React 组件中执行过数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。
useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。
很多情况下,我们希望在组件加载和更新时执行同样的操作
使用 useEffect 重构
useEffect 将书写的代码逻辑做了改变:由关心生命周期的逻辑,变成了 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。
Effect只需要
componentDidMount
Effect只需要
componentDidUpdate
只需要更新后执行,这种场景应该很少吧,方法很丑,不用,不用。
Effect卸载阶段
使用 Effect return 一个函数调用表示组件即将卸载阶段的调用,模拟
componentWillUnmount
Effect更新阶段性能优化(简单版)
在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。在 class 组件中,我们可以通过在 componentDidUpdate 中添加对 prevProps 或 prevState 的比较逻辑解决:
使用 useEffect,如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可:
Effect更新阶段性能优化(复杂版),模拟
shouldComponentUpdate
自定义 Hook
Hook 规则
从 Class 迁移到 Hook
生命周期方法要如何对应到 Hook?
我该如何使用 Hook 进行数据获取?
该 demo 会帮助你开始理解。欲了解更多,请查阅 此文章 来了解如何使用 Hook 进行数据获取。
展望
Hook
Suspense 异步获取 的进展
参考链接
The text was updated successfully, but these errors were encountered: