欢迎来到我的博客
博主是一名大学在读本科生,主要学习方向是前端。
目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏
目前正在学习的是 R e a c t 框架 React框架 React框架,中间穿插了一些基础知识的回顾
博客主页codeMak1r.小新的博客本文目录
- Hooks进阶
- 1.useState - 回调函数的参数
- 来个需求
- 2.useEffect - 清理副作用
- 3.useEffect - 发送网络请求
- 4.useRef
- 5.useContext
本文被专栏【React–从基础到实战】收录
阶段目标:
能够理解useState回调函数作为参数的使用场景
使用场景
参数只会在组件初次渲染中起作用,后续渲染时会被忽略。如果初始 state 需要通过计算才能获得,则可以传入一个函数,在函数中计算并返回初始的state,此函数只在初始渲染时被调用
语法
const [ name, setName ] = useState( () => {
// 在这里编写计算逻辑
return '计算之后的初始值'
})
语法规则
name
的初始值语法选择
useState(defaultValue)
即可useState( () => {} )
页面中存在两个按钮,一个初始值为10,另一个初始值为20;另外两个按钮点击后都会有自增+1的效果。
// Counter组件
import { useState } from 'react'
export default function Counter(props) {
const [count, setCount] = useState(() => {
// 回调形式的useState,返回值为初始值
return props.count
})
return (
<button style={{
backgroundColor: 'skyblue', width: '100px', height: '60px', margin: '20px'
}} onClick={() => setCount(count + 1)}>{count}</button>
)
}
// App组件
import React, { Fragment } from 'react'
import Counter from './components/11_hooks_Counter'
export default function App() {
return (
<div>
<Counter count={10} />
<Counter count={20} />
</div>
)
}
阶段目标:
能够掌握清理useEffect的方法
使用场景
在组件被销毁时,如果有些副作用操作需要被清理,就可以使用此语法,比如常见的定时器
语法及规则
useEffect(() => {
console.log("副作用函数执行了!")
// 副作用函数的执行时机为:在下一次副作用函数执行之前执行
return () => {
console.log("清理副作用的函数执行了!")
// 在这里写清理副作用的代码
}
})
定时器小案例
添加副作用函数前:组件虽然已经不显示了,但是定时器依旧在运行
import { useEffect,useState } from 'react'
function Foo() {
useEffect( () => {
let timer = setInterval( () => {
console.log('副作用函数执行了')
}, 1000)
return () => {
clearInterval(timer)
}
}, [])
}
添加清理副作用函数后:一旦组件被销毁,定时器也被清理
阶段目标:
能够掌握使用useEffect hook 发送网络请求
使用场景
如何在useEffect中发送网络请求,并且封装同步 async/await
操作
语法要求
不可以直接在useEffect的回调函数外层直接包裹 await,因为异步会导致清理函数无法立即返回
useEffect(async () => {
const res = await axios.get('http://geek.itheima.net/v1_0/channels')
console.log(res)
},[])
正确写法
在内部单独定义一个函数,然后把这个函数包装成同步
useEffect(() => {
async function fetchData() {
const res = await axios.get('http://geek.itheima.net/v1_0/channels')
console.log(res)
}
fetchData()
}, [])
阶段目标:
能够掌握使用useRef获取真实dom或组件实例的方法
使用场景
在函数组件中获取真实的dom元素对象或者组件对象
使用步骤
useRef
函数useRef
函数并传入null,返回值为一个对象,内部有一个current
属性存放拿到的dom对象(组件实例)获取dom
import { useEffect, useRef } from 'react'
function App() {
const h1Ref = useRef(null)
useEffect(() => {
console.log(h1Ref)
},[])
return (
<div>
<h1 ref={ h1Ref }>this is h1</h1>
</div>
)
}
export default App
获取组件实例
函数组件由于没有实例,不能使用ref获取,如果想获取组件实例,必须是类组件
class Foo extends Component {
sayHi = () => {
console.log('say hi')
}
render(){
return <div>Foo</div>
}
}
export default Foo
import { useEffect, useRef } from 'react'
import Foo from './Foo'
function App() {
const h1Foo = useRef(null)
useEffect(() => {
console.log(h1Foo)
}, [])
return (
<div> <Foo ref={ h1Foo } /></div>
)
}
export default App
阶段目标:
能够掌握hooks下的context的使用方式
实现步骤
createContext
创建context对象Provider
提供数据useContext
函数获取数据代码实现
import { createContext, useState, useContext } from 'react'
const Context = createContext()
export default function Demo() {
const [count, setCount] = useState(0)
return (
<div>
<Context.Provider value={count}>
<ComA />
</Context.Provider>
</div>
)
}
function ComA() {
return (
<div>
<ComB />
</div>
)
}
function ComB() {
const count = useContext(Context)
return (
<div>
<h2>我是ComB组件,我爷爷传给我的context值为:{count}</h2>
</div>
)
}
如果有后代组件不在同一个文件中,只需要把创建的Context容器对象暴露出去即可。
export const Context = createContext()
在其他组件的文件中使用:
import React, { useContext } from 'react'
import { Context } from './index'
export default function ComC() {
const count = useContext(Context)
return (
<div>
{count}
</div>
)
}