概述
1.useState - 回调函数的参数
使用场景
参数只会在组件的初始渲染中起作用,后续渲染时会被忽略。如果初始 state 需要通过计算才能获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用
语法
const [name, setName] = useState(()=>{ // 编写计算逻辑 return '计算之后的初始值'})
语法规则
- 回调函数return出去的值将作为
name
的初始值 - 回调函数中的逻辑只会在组件初始化的时候执行一次
语法选择
- 如果就是初始化一个普通的数据 直接使用
useState(普通数据)
即可 - 如果要初始化的数据无法直接得到需要通过计算才能获取到,使用
useState(()=>{})
eg。
import { useState } from 'react'
// 计算的含义
function getDefaultValue(){
for(let i =0 ;i<1000;i++){
}
return '10'
}
function Counter(props) {
const [count, setCount] = useState(() => {
// 这里目的:为了体现初始值经过一定的计算
// 这个计算比较广义的概念
// 只要无法直接确定,需要通过一定的操作才能获取,
// 就可以理解为计算
// 循环遍历一万条数据,才能确定这里的初始值是什么
return props.count
------------------------
return getDefaultValue()
})
return (
<div>
<button onClick={() => setCount(count + 1)}>{count}</button>
</div>
)
}
function App() {
return (
<>
<Counter count={10} />
<Counter count={20} />
</>
)
}
export default App
2.useEffect - 清理副作用
有一些副作用是需要清除的,可以防止引起内存泄露。
1.使用场景
在组件被销毁时,如果有些副作用操作需要被清理,就可以使用此语法,比如常见的定时器
2.语法及规则
useEffect(() => {
console.log('副作用函数执行了')
// 副作用函数的执行时机为: 在下一次副作用函数执行之前执行
return () => {
console.log('清理副作用的函数执行了')
// 在这里写清理副作用的代码
}
})
3.代码复现:
import { useEffect, useState } from 'react'
function Test () {
//清除副作用effect
useEffect(() => {
let timer = setInterval(() => {
console.log('定时器执行了')
}, 1000)
return () => {//执行时机:React将会在执行清除操作时调用它--componentWillMount
//清理的动作
clearInterval(timer)
}
}, [])
return (
<div>this is test</div>
)
}
function App () {
const [flag, setFlag] = useState(true)
return (
<>
{flag ? <Test /> : null}
<button onClick={() => setFlag(!flag)}>switch</button>
</>
)}
将setFlag作为函数书写的案例:
import { useEffect, useState } from 'react'
function A () {
useEffect(() => {
let timer = setInterval(() => {
console.log(111)
}, 1000)
return () => {
clearInterval(timer)
}
})
return (
<div>
A组件
</div>
)
}
function App () {
const [isShow, setIsShow] = useState(true)
function changeA () {
setIsShow(false)
}
return (
<div>
{isShow ? <A /> : null}
<button onClick={changeA}>销毁A组件</button>
</div>
)}
3.定时器小案例
添加副作用函数前:组件虽然已经不显示了,但是定时器依旧在运行
import { useEffect, useState } from 'react'
function Foo() {
useEffect(() => {
setInterval(() => {
console.log('副作用函数执行了')
}, 1000)
})
return <div>Foo</div>
}
function App() {
const [flag, setFlag] = useState(true)
return (
<>
<button onClick={() => setFlag(false)}>click</button>
{flag ? <Foo/> : null}
</>
)
}
export default App
添加清理副作用函数后:一旦组件被销毁,定时器也被清理
import { useEffect, useState } from 'react'
function Foo() {
useEffect(() => {
const timerId = setInterval(() => {
console.log('副作用函数执行了')
}, 1000)
// 添加清理副租用函数
return () => {
clearInterval(timerId)
}
})
return <div>Foo</div>
}
function App() {
const [flag, setFlag] = useState(true)
return (
<>
<button onClick={() => setFlag(false)}>click</button>
{flag ? <Foo/> : null}
</>
)
}
export default App
4.useEffect - 发送网络请求
类组件如何发送网络请求?
发送网络请求的生命周期钩子函数:componentDidMount
执行时机?
在初始化的时候dom渲染完毕时,只执行一次
useEffect
- 不加依赖项 - 初始化 + 重新渲染
- 加[ ] - 初始化执行一次
- 加特定的依赖项[count,name] - 首次执行 +任意一个变化执行
1.使用场景
如何在useEffect中发送网络请求,并且封装同步 async await操作
2.语法要求
不可以直接在useEffect的回调函数外层直接包裹 await ,因为异步会导致清理函数无法立即返回
useEffect(async ()=>{
const res = await axios.get('http://geek.itheima.net/v1_0/channels')
console.log(res)
},[])
3.正确写法
在内部单独定义一个函数,然后把这个函数包装成同步
useEffect(()=>{
async function fetchData(){
// await fetch也可以,百度搜索
const res = await axios.get('http://geek.itheima.net/v1_0/channels')
console.log(res)
}
},[])
复制一张图片的地址,可以将图片请求出来:
function A () {
const [imgs, setImgs] = useState('')
useEffect(() => {
const res = fetch('https://fastly.jsdelivr.net/npm/@vant/assets/logo.png')
console.log(res)
res.then((value) => {
console.log(value)//返回的是一个结果
setImgs(value.url)
})
},[])
return (
<div>
A组件
<img src={imgs} alt="" />
</div>
)}
useEffect发送网络请求,只请求一次的话,依赖项就设置为空数组 。
5.useRef
useRef获取真实dom或组件实例。返回一个可变的ref对象,其中.current属性被初始化为传入的参数,
1.使用场景
在函数组件中获取真实的dom元素对象或者是组件对象
2.使用步骤
- 导入
useRef
函数 - 执行
useRef
函数并传入null,返回值为一个对象 内部有一个current属性存放拿到的dom对象(组件实例) - 通过ref 绑定 要获取的元素或者组件
3.获取dom
import { useEffect, useRef } from 'react'
class Test extends React.Component {
render () {
return (
<div>类组件</div>
)
}
}
function App() {
const testRef = useRef(null)
const h1Ref = useRef(null)
//useEffect回调:在dom渲染之后
// vue里的watch效果比较像,但执行时机时不同的
useEffect(() => {
console.log(testRef.current)
console.log(h1Ref.current)
console.log(h1Ref)
},[])
return (
<div>
<Test ref={testRef} />
<h1 ref={ h1Ref }>this is h1</h1>
</div>
)
}
export default App
在Test中加入函数,state等
state={
name:'zz'
}
getName=()=>{
return 'child test'
}
4.获取组件实例
函数组件由于没有实例,不能使用ref获取,如果想获取组件实例,必须是类组件
Foo.js
class Foo extends React.Component {
sayHi = () => {
console.log('say hi')
}
render(){
return <div>Foo</div>
}
}
export default Foo
App.js
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
5.useContext
在函数组件中跨组件通信
- 接收一个 context 对象(
React.createContext
的返回值)并返回该 context 的当前值。 - 当前的 context 值由上层组件中距离当前组件最近的
<MyContext.Provider>
的value
prop 决定。
1.实现步骤
- 使用
createContext
创建Context对象 - 在顶层组件通过
Provider
提供数据 - 在底层组件通过
useContext
函数获取数据
2.代码实现
import { createContext, useContext } from 'react'
// 1.创建Context对象
const Context = createContext()
function Foo() {
return <div>Foo <Bar/></div>
}
function Bar() {
// 3.底层组件通过useContext函数获取数据
// usseContext(createContext返回的对象)
//通过调用useContext,将Context对象传过去,得到当前的传过去的Context的值
const name = useContext(Context)
return <div>Bar {name}</div>
}
function App() {
return (
// 2.顶层组件通过Provider 提供数据
<Context.Provider value={'this is name'}>
<div><Foo/></div>
</Context.Provider>
)
}
export default App
3.单独写:
1.把createContext分装出去,创建context.js ---要记得都保存
import { createContext } from "react"
const Context = createContext()
export default Context
2.App.js引用context.js
import Context from './context'
完整代码:
import React, { useContext, useState } from 'react'
import Context from './context'
function ComA () {
const count = useContext(Context)
return (
<div>
ComA
<br />
app传过来的数据为:{count}
<ComC />
</div>
)
}
function ComC () {
const count = useContext(Context)
return (
<div>
ComC
<br />
app传过来的数据为:{count}
</div>
)
}
function App () {
const [count, setCount] = useState(20)
return (
<Context.Provider value={count}>
<div>
<ComA />
<button onClick={() => { setCount(count + 1) }}>+</button>
</div>
</Context.Provider>
)
}
export default App
4.也可以在index.js中使用createContext
1.index.js中引入context.js
import Context from './context'
2.除去App.js中的以下内容
<Context.Provider value={count}>
const [count, setCount] = useState(20)
3.index.js中添加
<React.StrictMode>
// 这个value只能传递一次,是什么就是什么
<Context.Provider value={100}>
<App />
</Context.Provider>
</React.StrictMode>,
context如果要传递的数据,只需要在整个应用初始化的时候传递一次就可以,可以选择在当前文件里做数据提供,index.js->静态的
context如果需要传递数据并且将来还需要再对数据做修改,底层组件也需要变,所以可以写到App.js中->动态的
阶段小练习-todoMvc-hook版
案例仓库地址:
react课程全系列/react-tomvc-hook
项目演示步骤:
- 克隆项目到本地
git clone https://gitee.com/react-course-series/react-tomvc-hook.git
- 安装必要依赖
yarn
- 开启mock接口服务,保持窗口不关闭 !!!!!
# 启动mock服务 yarn mock-serve
- 另起一个bash窗口开启前端服务
yarn start
- 浏览器输入 localhost:3000演示效果
项目开发步骤:
-
切换到todo-test分支
git checkout todo-test
-
打开 app.js
已有基础样板代码,在这个基础上编写业务逻辑即可
-
接口文档
接口作用 接口地址 接口方法 接口参数 获取列表 http://localhost:3001/data GET 无 删除 http://localhost:3001/data/:id DELETE id 搜索 http://localhost:3001/data/?q=keyword GET name(以name字段搜索)
实现功能
功能 | 核心思路 |
---|---|
表格数据渲染 | elementPlus el-table组件使用 |
删除功能 | 获取当前id 调用接口 |
搜索功能 | 用的依旧是列表接口,多传一个name参数 |
清除搜索功能 | 清空搜索参数 重新获取列表 |
最后
以上就是自信煎饼为你收集整理的Hooks进阶--useEffect - 发送网络请求1.useState - 回调函数的参数2.useEffect - 清理副作用3.定时器小案例4.useEffect - 发送网络请求5.useRef5.useContext1.实现步骤的全部内容,希望文章能够帮你解决Hooks进阶--useEffect - 发送网络请求1.useState - 回调函数的参数2.useEffect - 清理副作用3.定时器小案例4.useEffect - 发送网络请求5.useRef5.useContext1.实现步骤所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复