Custom hooks is an extension based on React Hooks. We can formulate combined hooks that meet business needs according to business needs, and pay more attention to logical units. How to encapsulate a piece of logic and achieve reuse is the original intention of custom hooks.
Custom hooks can also be said to be the aggregation product of React Hooks, which consists of one or more React Hooks to solve some complex logic.
A traditional custom hook looks like this:
function useXXX(参数A, 参数B, ...) {
/*
实现自定义 hooks 逻辑
内部应用了其他 React Hooks
*/
return [xxx, ...]
}
use:
const [xxx, ...] = useXXX(参数A, 参数B, ...)
Custom hooks parameters may be the following:
hooks
initialization valueCallback functions for some side effects or events
Can be the element or component instance
useRef
obtainedDOM
no parameters required
The return value of custom hooks may be the following:
Responsible for rendering the state obtained by the view
update function component method, essentially
useState
eitheruseReducer
Some state passed to descendant components
no return value
characteristic
First of all, we need to understand that the custom hooks written by developers are essentially functions and are executed in function components. Custom hooks driver is essentially the execution of function components .
driving conditions
There are two main driving conditions for custom hooks:
props
Changes brought about by function component execution.
useState
OruseReducer
changestate
causes an update of the function component.
sequence principle
There must be at least one React Hooks inside the custom hooks, so the custom hooks must also follow the rules of React Hooks, they cannot be placed in conditional statements, and the consistency of execution order must be maintained. Why is this?
This is because during the update process, if the hooks are added or deleted through the if conditional statement, then in the process of reusing the hooks, the state of the reusable hooks will be inconsistent with the current hooks. Therefore, we must pay attention to the consistency of the order of hooks during development.
practice
Next, let's implement a custom hooks that can automatically report page views | click time -- useLog
.
Through this custom hooks, you can control the monitoring of DOM elements and distinguish dependencies .
Write custom hooks:
export const LogContext = createContext({});
export const useLog = () => {
/* 定义一些公共参数 */
const message = useContext(LogContext);
const listenDOM = useRef(null);
/* 分清依赖关系 */
const reportMessage = useCallback(
function (data, type) {
if (type === "pv") {
// 页面浏览量上报
console.log("组件 pv 上报", message);
} else if (type === "click") {
// 点击上报
console.log("组件 click 上报", message, data);
}
},
[message]
);
useEffect(() => {
const handleClick = function (e) {
reportMessage(e.target, "click");
};
if (listenDOM.current) {
listenDOM.current.addEventListener("click", handleClick);
}
return function () {
listenDOM.current &&
listenDOM.current.removeEventListener("click", handleClick);
};
}, [reportMessage]);
return [listenDOM, reportMessage];
};
In the above code, the following 4 React Hooks are used:
Use
useContext
the public information of the buried point, and when the public information changes, it will be updated uniformly.Use
useRef
to get the DOM element.Use
useCallback
the cache report informationreportMessage
method to get the content insideuseContext
. Ascontext
a dependency, when the dependency changes,reportMessage
the function is redeclared.Use
useEffect
listener DOM event, use itreportMessage
as a dependency,useEffect
perform event binding in it, and return the destroy function for unbinding.
Dependency : context
change -> let the context
imported reportMessage
redeclaration -> let the binding DOM event listener useEffect
be able to bind the latest reportMessage
Use custom hooks:
import React, { useState } from "react";
import { LogContext, useLog } from "./hooks/useLog";
const Home = () => {
const [dom, reportMessage] = useLog();
return (
<div>
{/* 监听内部点击 */}
<div ref={dom}>
<button> 按钮 1 (内部点击) </button>
<button> 按钮 2 (内部点击) </button>
<button> 按钮 3 (内部点击) </button>
</div>
{/* 外部点击 */}
<button
onClick={() => {
console.log(reportMessage);
}}
>
外部点击
</button>
</div>
);
};
// 阻断 useState 的更新效应
const Index = React.memo(Home);
const App = () => {
const [value, setValue] = useState({});
return (
<LogContext.Provider value={value}>
<Index />
<button onClick={() => setValue({ cat: "小猫", color: "棕色" })}>
点击
</button>
</LogContext.Provider>
);
};
export default App;
As above, when context
a change occurs, the effect of normal reporting can be achieved. Small details: Use React.memo
to block the update effect of App
component changes state
on Home
components.
result
At the beginning, click the buttons 1, 2, and 3 in sequence, and the effect is as follows:
After clicking the button, and then clicking buttons 1, 2, and 3 in sequence, the effect is as follows: