将OneNote笔记与Word文档链接的两种方法(onenote怎样打开word文档)
720
2022-05-30
文章出处: 拉 勾 大前端 高薪训练营
1. React Hooks 介绍
对函数型组件进行增强,让函数型组件可以存储状态,可以拥有处理副作用的能力,让开发者在不使用类组件的情况下,实现相同的功能。
缺少逻辑复用的机制
为了复用逻辑增加无实际渲染效果的组件,增加了组件层级,显示十分臃肿,增加了调试的难度以及运行效率的降低
类组件经常会变得很复杂难以维护
将一组相干的业务逻辑拆分到了多个生命周期函数中,在一个生命周期函数内,存在多个不相干的业务逻辑
类成员方法不能保证 this 指向的正确性
2. React Hooks 使用
Hooks 意为钩子, React Hooks 就是一堆钩子函数, React 通过这些钩子函数对函数型组件进行增强,不同的钩子函数提供了不同的功能
用于为函数组件引入状态
import {useState} from 'react' function App() { const [count, setCount] = useState(0) return (
1
2
3
4
5
6
7
8
9
10
11
12
13
接受唯一的参数即状态初始值,初始值可以是任意数据类型。
const [count, setCount] = useState(0) const [person, setPerson] = useState({ name: '张三', age: 20 })
1
2
返回值为数组,数组中存储值和更改状态值的方法,方法名称约定以 set 开头,后面加上状态名称。
const [count, setCount] = useState(0)
1
方法可以被调用多次,用以保存不同状态值
1
2
3
参数可以是一个函数,函数返回什么,初始状态值就是什么,函数只会被调用一次,在初始值是动态值的情况。
// 当初始值是动态值 // 这样写每次渲染都会执行 const propsCount = props.count || 0 // const [count, setCount] = useState(propsCount) // 应该这样写 const [count, setCount] = useState(() => { return props.count || 0 // 只有第一次执行的时候才会执行 })
1
2
3
4
5
6
7
8
9
设置状态值方法的参数可以是一个值也可以是一个函数,设置状态值方法的方法本身是异步的
如果代码依赖状态值,那要写在回调函数中:
function handleCount () { setCount((count) => { const newCount = count + 1 document.title = newCount return newCount }) }
1
2
3
4
5
6
7
8
9
useReducer 是另一种让函数组件保存状态的方式,可以将 dispatch 传给子组件使用
import { useReducer } from "react"; export default function App () { function reducer (state, action) { switch (action.type) { case 'increment': return state + 1 case 'decrement': return state - 1 default: return state; } } const [count, dispatch] = useReducer(reducer, 0) return (
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
在跨组件层级获取数据时简化获取数据的代码
import { createContext, useContext } from "react"; const countContext = createContext() export default function App () { return (
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
让函数型组件拥有处理副作用的能力,类似生命周期函数
useEffect 执行机制
可以把 useEffect 看做 componentDidMount, componentDidUpdate 和 componentWillUnmount 这三个函数的组合
useEffect(() => {}) => componentDidMount, componentDidUpdate
useEffect(() => {}, []) => componentDidMount
useEffect(() => () => {}) => componentDidUpdate, componentWillUnmount
useEffect(() => () => {}, []) => componentWillUnmount
import { useEffect, useState } from "react"; import ReactDOM from 'react-dom' export default function App () { const [count, setCount] = useState(0) // 组件挂载完成之后执行,组件数据更新之后执行 // useEffect(() => { // console.log('123') // }) // 组件挂载完成之后执行 // useEffect(() => { // console.log('456') // }, []) useEffect(() => { return () => { console.log('组件被卸载了') } }) return (
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
useEffect 使用方法
(1). 为 window 对象添加滚动事件
(2). 设置定时器让 count 数值每隔一秒增加 1
import { useEffect, useState } from "react"; import ReactDOM from 'react-dom' export default function App () { const [count, setCount] = useState(0) function onScroll () { console.log('页面滚动了') } useEffect(() => { window.addEventListener('scroll', onScroll) return () => { window.removeEventListener('scroll', onScroll) } }, []) useEffect(() => { const timerId = setInterval(() => { setCount(count => { const newCount = count + 1 document.title = newCount return newCount }) }, 1000); return () => { clearTimeout(timerId) } }, []) return (
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
useEffect 解决的问题
(1). 按照用途将代码进行分类(将一组相同的业务逻辑归置到了同一个副作用函数中)
(2). 简化重复代码,是组件内部代码更加清晰
只有指定数据发生变化时触发 effect
import { useEffect, useState } from "react"; export default function App () { const [count, setCount] = useState(0) const [person, setPerson] = useState({name: '张三'}) useEffect(() => { // person 的变化不会触发 useEffect , 因为第二个数组参数中只监听了 count document.title = count console.log(111) }, [count]) return (
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
useEffect 钩子函数结合异步函数
useEffect 中的参数函数不能是异步函数,因为 useEffect 函数要返回清理资源的函数,如果是异步函数就变成了返回 Promise. 可以写成自执行函数的形式:
useEffect(() => { (async () => { await axios.get() })() }, [])
1
2
3
4
5
useMemo 的行为类似 Vue 中的计算属性,可以检测某个值的变化,根据变化只计算新值。
useMemo 会缓存计算结果,如果检测子没有发生变化,及时组建重新渲染,也不会重新计算,此行为可以有助于避免在每个渲染上进行昂贵的计算。
import { useState, useMemo } from "react"; export default function App () { const [count, setCount] = useState(0) const [bool, setBool] = useState(true) const result = useMemo(() => { console.log('111') // 只有 count 改变才会重新执行这个回调函数 return count * 2 }, [count]) return (
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
性能优化,如果本组件中的数据没有发生变化,阻止组件更新,类似类组件中的 PureComponent 和 shouldComponentUpdate
import { memo } from 'react' const Foo = memo(function Foo () { return
1
2
3
4
5
性能优化,缓存函数,使用组件重新渲染时得到相同的函数实例。否则每次父组件渲染,函数变量的实例都会变化,导致里层组件被重新渲染
import { useState, memo, useCallback } from "react"; const Foo = memo(function Foo (props) { console.log('Foo 重新渲染了') return
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { useRef } from "react"; export default function App () { const box = useRef() return (
1
2
3
4
5
6
7
8
9
10
即使组件重新渲染,保存的数据仍然还在,保存的数据被更改不会触发组件重新渲染。
import { useRef, useState, useEffect} from "react"; export default function App () { const [count, setCount] = useState(0) let timeId = useRef() // 夸组件生命周期 useEffect(() => { // 使用这个 ref 的 current 属性存储数据 timeId.current = setInterval(() => { setCount(count => count + 1) }, 1000); }, []) const stopCount = () => { console.log(timeId.current) clearInterval(timeId.current) } const box = useRef() return (
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
3. 自定义 Hook (为了在组件之间形成逻辑共享)
自定义 Hook 是标准的封装和共享逻辑的方式
自定义 Hook 是一个函数,其名称以 use 开头
自定义 Hook 其实就是逻辑和内置 Hook 的组合
如何使用自定义 Hook:
import { useState, useEffect} from "react"; import axios from "axios"; function useGetPost () { const [post, setPost] = useState({}) useEffect(() => { axios.get('https://jsonplaceholder.typicode.com/posts/1') .then((response) => { setPost(response.data) }) }, []) return [post, setPost] } export default function App () { const [post, setPost] = useGetPost() return (
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
封装公共逻辑:
import { useState} from "react"; function useUpdateInput (initialState) { const [value, setValue] = useState(initialState) return { value, onChange: e => setValue(e.target.value) } } export default function App () { const usernameInput = useUpdateInput('') const passwordInput = useUpdateInput('') const submitForm = event => { event.preventDefault(); console.log(usernameInput.value) console.log(passwordInput.value) } return (
) }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
4. React 路由 Hooks
index.js
import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter as Router } from "react-router-dom"; import App from './App'; ReactDOM.render(
1
2
3
4
5
6
7
8
9
10
11
App.js
import { Link, Route } from "react-router-dom"; import Home from './pages/Home' import List from './pages/List' export default function App () { return ( <>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Home.js
import { useHistory, useLocation, useRouteMatch, useParams } from "react-router-dom"; export default function Home(props) { console.log(props) console.log(useHistory()) console.log(useLocation()) console.log(useRouteMatch()) console.log(useParams()) return
1
2
3
4
5
6
7
8
9
10
11
12
输出结果:
{history: {…}, location: {…}, match: {…}, staticContext: undefined}
{length: 7, action: “PUSH”, location: {…}, createHref: ƒ, push: ƒ, …}
{pathname: “/home/zhangsan”, search: “”, hash: “”, state: undefined, key: “o6w5y3”}
{path: “/home/:name”, url: “/home/zhangsan”, isExact: true, params: {…}}
{name: “zhangsan”}
List.js
export default function List(props) { console.log(props) return
1
2
3
4
5
6
使用数组 state 存储状态,用数组 setters 存储 setState方法,利用闭包管理,将 下标 stateIndex 缓存在闭包中,创建 对应的 setState.
// import { useState } from 'react' import ReactDOM from 'react-dom' let state = [] let setters = [] let stateIndex = 0 function createSetter (index) { return function (newState) { state[index] = newState render() } } function useState (initialState) { state[stateIndex] = state[stateIndex] ? state[stateIndex] : initialState setters.push(createSetter(stateIndex)) let value = state[stateIndex] let setter = setters[stateIndex] stateIndex ++ return [value, setter] } function render () { stateIndex = 0 ReactDOM.render(
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// import { useState } from 'react' import ReactDOM from 'react-dom' let state = [] let setters = [] let stateIndex = 0 function createSetter (index) { return function (newState) { state[index] = newState render() } } function useState (initialState) { state[stateIndex] = state[stateIndex] ? state[stateIndex] : initialState setters.push(createSetter(stateIndex)) let value = state[stateIndex] let setter = setters[stateIndex] stateIndex ++ return [value, setter] } function render () { stateIndex = 0 effectIndex = 0 ReactDOM.render(
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// import { useState } from 'react' // import { useReducer } from 'react' import ReactDOM from 'react-dom' let state = [] let setters = [] let stateIndex = 0 function createSetter (index) { return function (newState) { state[index] = newState render() } } function useState (initialState) { state[stateIndex] = state[stateIndex] ? state[stateIndex] : initialState setters.push(createSetter(stateIndex)) let value = state[stateIndex] let setter = setters[stateIndex] stateIndex ++ return [value, setter] } function render () { stateIndex = 0 effectIndex = 0 ReactDOM.render(
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
React 数据结构
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。