Hooks是可复用的函数,允许您在不编写类的情况下使用状态和其他功能(例如生命周期方法等)。Hook函数使我们能够使用函数组件“钩入”React状态生命周期,从而允许我们操作函数组件的状态,而无需将其转换为类组件。
React在16.8版本中引入了Hooks,并从那时起不断添加更多Hooks。一些Hooks比其他Hooks更常用和流行,例如useEffect
、useState
和useContext
。如果您使用React,我相信您一定用过这些Hooks。
但我感兴趣的是鲜为人知的React Hooks。虽然所有React Hooks都各有特色,但我真正想向您展示五个Hooks,因为它们可能不会出现在您的日常工作中——或者也许会,了解它们会赋予您一些额外的超能力。
useReducer
useRef
useImperativeHandle
useMemo
useCallback
useReducer
useReducer
Hook是一个类似于其他Hook的状态管理工具。具体来说,它是useState
Hook的替代方案。
如果您使用useReducer
Hook来更改两个或多个状态(或操作),则无需单独操作这些状态。该Hook会跟踪所有状态并集体管理它们。换句话说:它管理和重新渲染状态更改。与useState
Hook不同,在处理复杂项目中的许多状态时,useReducer
更容易。
useReducer
可以帮助降低处理多个状态的复杂性。当您发现自己需要集体跟踪多个状态时,可以使用它,因为它允许您将组件的状态管理和渲染逻辑视为单独的关注点。
useReducer
接受三个参数,其中一个参数是可选的:
const [state, dispatch] = useReducer(reducer, initialState) const [state, dispatch] = useReducer(reducer, initialState, initFunction) // 使用可选的第三个参数进行初始化的情况
以下示例是一个包含文本输入、计数器和按钮的界面。与每个元素交互都会更新状态。请注意,useReducer
允许我们一次定义多个情况,而不是单独设置它们。
import { useReducer } from 'react'; const reducer = (state, action) => { switch (action.type) { case 'INCREMENT': return { ...state, count: state.count 1 }; case 'DECREMENT': return { ...state, count: state.count - 1 }; case 'USER_INPUT': return { ...state, userInput: action.payload }; case 'TOGGLE_COLOR': return { ...state, color: !state.color }; default: throw new Error(); } } function App() { const [state, dispatch] = useReducer(reducer, { count: 0, userInput: '', color: false }) return ( <main classname="App App-header" style="{{" backgroundcolor: state.color :> <input type="text" onchange="{(e)"> dispatch({ type: 'USER_INPUT', payload: e.target.value })} /> <br><br><p style="{{" margin:>{state.count}</p> <button onclick="{()"> dispatch({ type: 'DECREMENT' })}>-</button> <button onclick="{()"> dispatch({ type: 'INCREMENT' })}> </button> <button onclick="{()"> dispatch({ type: 'TOGGLE_COLOR' })}>Color</button> <br><br><p style="{{" margin:>{state.userInput}</p> </main> ); } export default App;
从上面的代码中,您可以注意到我们能够轻松地在reducer
(switch-case)中管理多个状态,这展示了useReducer
的优势。在具有多个状态的复杂应用程序中工作时,这就是它提供的强大功能。
useRef
useRef
Hook用于在元素上创建引用,以便访问DOM。但不仅如此,它还返回一个具有.current
属性的对象,该属性可以在组件的整个生命周期中使用,允许数据持久化而不会导致重新渲染。因此,useRef
值在渲染之间保持不变;更新引用不会触发重新渲染。
当您想要:
可以使用useRef
Hook。它在存储应用程序中的可变数据而不导致重新渲染时最有用。
useRef
只接受一个参数,即初始值。
const newRefComponent = useRef(initialValue);
在这里,我使用了useRef
和useState
Hook来显示应用程序在文本输入中键入时重新渲染更新状态的次数。
import './App.css' function App() { const [anyInput, setAnyInput] = useState(" "); const showRender = useRef(0); const randomInput = useRef(null); // 注意这里需要设置null const toggleChange = (e) => { setAnyInput(e.target.value); showRender.current ; } const focusRandomInput = () => { if (randomInput.current) { // 添加判断,防止null引用错误 randomInput.current.focus(); } } return ( <div classname="App"> <h3>Amount Of Renders: {showRender.current}</h3> <input type="text" ref="{randomInput}" onchange="{toggleChange}"> <button onclick="{focusRandomInput}">Click To Focus On Input</button> </div> ); } export default App;
请注意,在文本字段中键入每个字符都会更新应用程序的状态,但不会触发完全重新渲染。
useImperativeHandle
您知道子组件如何访问从父组件传递给它们的功能吗?父组件通过props传递这些功能,但这种传递在某种意义上是“单向的”,因为父组件无法调用子组件中的函数。
那么,useImperativeHandle
使父组件能够访问子组件的函数成为可能。
这是如何工作的?
forwardRef
,允许将定义的ref传递给子组件。useImperativeHandle
通过ref公开子组件的函数。当您希望父组件受子组件中更改的影响时,useImperativeHandle
效果很好。因此,诸如更改焦点、递增和递减以及模糊元素的情况可能是您发现自己需要使用此Hook的情况,以便相应地更新父组件。
useImperativeHandle(ref, createHandle, [dependencies])
在此示例中,我们有两个按钮,一个在父组件中,一个在子组件中。单击父按钮可以从子组件检索数据,从而允许我们操作父组件。它的设置方式是单击子按钮不会将任何内容从父组件传递到子组件,以帮助说明我们如何以相反的方向传递内容。
// Parent component import React, { useRef } from "react"; import ChildComponent from "./childComponent"; import './App.css'; function ParentComponent() { const controlRef = useRef(null); return ( <div> <button onclick="{()"> { if (controlRef.current) { controlRef.current.controlPrint(); } }}>Parent Box</button> <childcomponent ref="{controlRef}"></childcomponent> </div> ); } export default ParentComponent;
// Child component import React, { forwardRef, useImperativeHandle, useState } from "react"; const ChildComponent = forwardRef((props, ref) => { const [print, setPrint] = useState(false); useImperativeHandle(ref, () => ({ controlPrint() { setPrint(!print); }, })); return ( <div> <button>Child Box</button> {print && <p>I am from the child component</p>} </div> ); }); export default ChildComponent;
...(此处应包含示例输出截图或描述)
useMemo
useMemo
是最不常用但最有趣的React Hooks之一。它可以提高性能并减少延迟,尤其是在应用程序中的大型计算中。怎么会这样呢?每次组件的状态更新和组件重新渲染时,useMemo
Hook都会阻止React重新计算值。
您会看到,函数会响应状态更改。useMemo
Hook接受一个函数并返回该函数的返回值。它缓存该值以防止花费额外的工作来重新渲染它,然后在其中一个依赖项发生更改时返回它。
此过程称为记忆化,它有助于通过记住先前请求的值来提高性能,以便可以再次使用它而无需重复所有这些计算。
最佳用例将是任何时候您都在处理繁重的计算,您希望存储该值并在后续状态更改中使用它。它可以带来不错的性能提升,但过度使用它可能会产生完全相反的效果,从而占用应用程序的内存。
useMemo(() => { // 代码在此处 }, [])
单击按钮时,此小型程序会指示数字是偶数还是奇数,然后对该值进行平方。我在循环中添加了许多零以增加其计算能力。它在几秒钟内返回该值,并且由于useMemo
Hook而仍然运行良好。
// UseMemo.js import React, { useState, useMemo } from 'react' function Memo() { const [memoOne, setMemoOne] = useState(0); const incrementMemoOne = () => { setMemoOne(memoOne 1) } const isEven = useMemo(() => { let i = 0; while (i < 1000000000) { i } //增加计算量 return memoOne % 2 === 0; }, [memoOne]); const squaredNumber = useMemo(() => { let i = 0; while (i < 1000000000) { i } //增加计算量 console.log("squared the number"); return memoOne * memoOne; }, [memoOne]); return ( <div> <h1>{memoOne}</h1> <button onClick={incrementMemoOne}>Increment</button> <p>Is Even: {isEven ? 'Yes' : 'No'}</p> <p>Squared Number: {squaredNumber}</p> </div> ); } export default Memo;
...(此处应包含示例输出截图或描述)
useMemo
有点像useCallback
Hook,但不同之处在于useMemo
可以存储来自函数的记忆化值,而useCallback
存储并返回函数本身。
useCallback
useCallback
Hook是另一个有趣的Hook,上一节是对其功能的剧透。
正如我们刚刚看到的,useCallback
的工作方式与useMemo
Hook类似,因为它们都使用记忆化来缓存某些内容以供以后使用。useMemo
将函数的计算存储为缓存值,而useCallback
存储并返回函数。
与useMemo
一样,useCallback
是一种不错的性能优化,因为它存储并返回记忆化的回调及其任何依赖项,而无需重新渲染。
const getMemoizedCallback = useCallback( () => { doSomething() }, [] );
import React, { useCallback, useState } from "react"; import CallbackChild from "./UseCallback-Child"; import "./App.css" export default function App() { const [toggle, setToggle] = useState(false); const [data, setData] = useState("I am a data that would not change at every render, thanks to the useCallback"); const returnFunction = useCallback( (name) => { return data name; }, [data] ); return ( <div> <button onclick="{()"> { setToggle(!toggle); }}> {/* Click To Toggle */} </button> {toggle && <h1>Toggling me no longer affects any function</h1>} <callbackchild returnfunction="{returnFunction}"></callbackchild> </div> ); }
// 子组件
import React, { useEffect } from "react"; function CallbackChild({ returnFunction }) { useEffect(() => { console.log("FUNCTION WAS CALLED"); }, [returnFunction]); return <p>{returnFunction(" Hook!")}</p>; } export default CallbackChild;
...(此处应包含示例输出截图或描述)
就是这样!我们刚刚查看了五个我认为经常被忽视的非常方便的React Hooks。与许多这样的综述一样,我们只是触及了这些Hooks的表面。它们各自都有自己的细微之处和注意事项,在使用它们时需要考虑。但希望您对它们是什么以及何时比您可能更经常使用的其他Hook更适合有一个很好的高级概念。
充分理解它们的最佳方法是实践。因此,我鼓励您在您的应用程序中练习使用这些Hooks以更好地理解它们。为此,您可以通过查看以下资源来更深入地了解:
<code>- Intro to React Hooks (Kingsley Silas) - Hooks at a Glance (React documentation) - Hooks Cheatsheet (Ohans Emmanuel) - The Circle of a React Lifecycle (Kingsley Silas) - Hooks of React Router (Agney Menon) - Testing React Hooks With Enzyme and React Testing Library (Kingsley Silas)</code>
以上是React钩子:深切口的详细内容。更多信息请关注PHP中文网其他相关文章!