- 作者:老汪软件技巧
- 发表时间:2024-08-22 07:05
- 浏览量:
useState 回调函数参数
用法: 能够给useState通过回调函数的形式给useState提供初始参数。
介绍:useState 的参数可以有两种形式:
1. useState(普通的数据) => useState(0) / useState('abc')
2. useState(回调函数) => useState(() => { return 初始值 })
在 useState(回调函数) 中,回调函数的返回值就是状态的初始值, 该回调函数只会触发一次。
使用 回调函数 来为 useState 初始化默认值
回调函数的返回值就是状态的初始值!
注意:该回调函数只会触发一次
const [list, setList] = useState(() => {
return JSON.parse(localStorage.getItem('comments')) || comments
})
该使用哪种形式?
如果状态就是一个普通的数据(比如,字符串、数字、数组等)都可以直接使用 useState(普通的数据)如果状态是经过一些计算得到的,此时,推荐使用 useState(回调函数)第一种:
const [list, setList] = useState(
JSON.parse(localStorage.getItem('list')) || arr
)
可以转化为:
这种情况下,只要组件更新,此处的 localStorage 等操作就会重复执行
const initList = JSON.parse(localStorage.getItem('list')) || comments
const [list, setList] = useState(initList)
第二种:
这种方式,因为回调函数只会执行一次,所以,此处的 localStorage 等操作代码只会执行一次
const [list, setList] = useState(() => {
return JSON.parse(localStorage.getItem('comments')) || comments
})
所以在这种情况下,推荐使用第二种方式
useEffect清理副作用
用法: 能够在组件卸载的时候,清除注册的事件
介绍: useEffect 的返回值是可选的,可省略。也可以返回一个清理函数,用来执行事件解绑等清理操作。
清理函数的执行时机:
建议:一个 useEffect 只处理一个功能,有多个功能时,使用多次 useEffect
useEffect(() => {
const handleResize = () => {}
window.addEventListener('resize', handleResize)
// 这个返回的函数,会在该组件卸载时来执行
// 因此,可以去执行一些清理操作,比如,解绑 window 的事件、清理定时器 等
return () => window.removeEventListener('resize', handleResize)
})
获取当前鼠标位置
案例: 能够实现让图片跟随鼠标移动
介绍:
import { useEffect, useState } from 'react'
import img from './1.gif'
export default function Move() {
const [position, setPosition] = useState({
x: 0,
y: 0
})
useEffect(() => {
const move = (e) => {
console.log('开始运动')
setPosition({
x: e.pageX,
y: e.pageY
})
}
document.addEventListener('mousemove', move)
console.log('触发注册事件')
return function () {
document.removeEventListener('mousemove', move)
}
}, [])
return (
<div>
<img
src={img}
style={{
position: 'absolute',
top: position.y + 1,
left: position.x + 1
}}
alt=""
/>
div>
)
}
自定义hooks
目标: 能够使用自定义hooks实现状态的逻辑复用
内容: 除了使用内置的 Hooks 之外,还可以创建自己的 Hooks(自定义 Hooks)。
useXxx 使用场景: 将组件状态逻辑提取到可重用的函数(自定义 Hooks)中,实现状态逻辑复用。
内置 Hooks 为函数组件赋予了 class 组件的功能;在此之上,自定义 Hooks 针对不同组件实现不同状态逻辑复用。
// 使用hooks实现猫跟着鼠标移动
import { useEffect, useState } from 'react'
export default function useMouse() {
const [position, setPosition] = useState({
x: 0,
y: 0,
})
useEffect(() => {
const move = (e) => {
setPosition({
x: e.pageX,
y: e.pageY,
})
}
document.addEventListener('mousemove', move)
return () => {
document.removeEventListener('mousemove', move)
}
}, [])
return position
}
useEffect发送请求
目的: 能够在函数组件中通过useEffect发送ajax请求
内容: 在组件中,使用 useEffect Hook 发送请求获取数据(side effect):
错误演示:
// 不要给 effect 添加 async
useEffect(async () => {
const res = awiat xxx()
return ()=> {
}
}, [])
正确使用:
useEffect(() => {
async function fetchMyAPI() {
let url = 'http://something/' + productId
let config = {}
const response = await myFetch(url)
}
fetchMyAPI()
}, [productId])
useRef 操作DOM
目标: 能够使用useRef操作DOM
内容: 在 React 中进行 DOM 操作时,用来获取 DOM
作用:返回一个带有 current 属性的可变对象,通过该对象就可以进行 DOM 操作了。
const inputRef = useRef(null)
解释:
/*
1. 使用useRef能够创建一个ref对象, 有current属性 {current: null}
const xxRef = useRef(null)
2. 通过ref属性关联到某个DOM对象上 {current: DOM}
3. 可以通过 xxRef.current访问到对应的DOM
*/
const App = () => {
const inputRef = useRef(null)
const add = () => {
console.log(inputRef.current.value)
}
return (
<section className="todoapp">
<input type="text" placeholder="请输入内容" ref={inputRef} />{' '}
<button onClick={add}>添加button>
section>
)
}
export default App
useContext-context
目标:实现跨级组件通讯
内容
useContext的用法useContext与的区别
1、 :在 JSX 标签内获取 Context 数据。
2、 useContext: 在 JavaScript 代码块中获取 Context 数据。
使用场景Context 的作用Context 对象包含的两个主要部分
Provider 组件
Consumer 组件
Consumer 组件行为有 Provider 时: 如果一个 Consumer 组件位于一个 Provider 的后代组件中,则它将获取到该 Provider 的value属性的值。无 Provider 时: 如果一个 Consumer 组件没有被任何 Provider 包裹,则它将获取到createContext创建时提供的defaultValue。示例
为了更好地理解如何使用 Context 和 useContext,下面是一个简单的示例:
import React, { createContext, useContext } from 'react';
// 创建 Context
const ThemeContext = createContext();
// Provider 组件
function ThemeProvider({ children }) {
return (
<ThemeContext.Provider value="dark">
{children}
ThemeContext.Provider>
);
}
// 使用 useContext 的函数组件
function Navbar() {
const theme = useContext(ThemeContext);
return (
<div>
<h1>The current theme is: {theme}h1>
div>
);
}
// 主组件
function App() {
return (
<ThemeProvider>
<Navbar />
ThemeProvider>
);
}
export default App;
Context 作用是实现跨组件传递数据,而不必在每个级别手动传递 props,简化组件之间的数据传递过程,那么使用Context 和不使用的区别在哪里呢 ?
不使用Context的情况(传统的Props Drilling)
父组件 (Parent Component)
中间组件 (Intermediate Component)
子组件 (Child Component)
这种情况下,数据必须从父组件层层传递到最底层的子组件,即使某些中间组件并不关心这些数据。这被称为“props drilling”。
描述
Parent Component
|
|--- Props
|
+-- Intermediate Component
|
|--- Props
|
+-- Child Component
|
|--- Uses Props
使用Context的情况
父组件 (Parent Component)
中间组件 (Intermediate Component)
子组件 (Child Component)
在这种情况下,数据通过Context Provider传递给整个组件树中的所有组件,不需要显式地在每一层都传递props。
描述
Parent Component
|
|--- Context Provider
|
+-- Intermediate Component
|
+-- Child Component
|
|--- useContext to access data
总结