Javascript 将对HTML元素的引用传递给自定义挂钩

Javascript 将对HTML元素的引用传递给自定义挂钩,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,假设我有一个自定义钩子,我将使用它将单击事件侦听器添加到HTML元素中 我使用constbuttonref=useRef(null)创建ref,因此第一次渲染时的值为空。ref值仅在render方法的最后一步中指定,即在已调用自定义挂钩的点处 因此,在第一次渲染时,我的自定义钩子没有任何可添加事件侦听器的内容 在自定义钩子第二次运行并最终将事件侦听器添加到元素之前,我必须更新组件。我得到以下行为: 问题: 如何避开这个问题?我真的需要强制更新我的组件以便向自定义挂钩发送引用吗?因为我只能在顶

假设我有一个自定义钩子,我将使用它将单击事件侦听器添加到HTML元素中

我使用
constbuttonref=useRef(null)创建ref,因此第一次渲染时的值为空。ref值仅在render方法的最后一步中指定,即在已调用自定义挂钩的点处

因此,在第一次渲染时,我的自定义钩子没有任何可添加事件侦听器的内容

在自定义钩子第二次运行并最终将事件侦听器添加到元素之前,我必须更新组件。我得到以下行为:

问题:

如何避开这个问题?我真的需要强制更新我的组件以便向自定义挂钩发送引用吗?因为我只能在顶层调用钩子和自定义钩子(钩子规则),所以下面这样的东西是不允许的

useEffect(() => {
  useMyHook();
});

App.js

function App() {
  const buttonRef = useRef(null);
  const hookValue = useMyHook(buttonRef.current);
  const [forceUpdate, setForceUpdate] = useState(false);

  return (
    <div>
      <button onClick={() => setForceUpdate(prevState => !prevState)}>
        Update Component
      </button>
      <button ref={buttonRef}>Update Hook</button>
      {"This is hook returned value: " + hookValue}
    </div>
  );
}
import { useEffect, useState } from "react";

function useMyHook(refEl) {
  const [myHookState, setMyHookState] = useState(0);

  console.log("Inside useMyhook...");
  console.log("This is the element received: ", refEl);

  useEffect(() => {
    const element = refEl.current;
    console.log("Inside useMyhook useEffect...");

    function onClick() {
      console.log("click");
      setMyHookState(prevState => prevState + 1);
    }
    console.log(element);
    if (element !== null) {
      element.addEventListener("click", onClick);
    }
    return () => {
      console.log("Inside useMyhook useEffect return...");
      if (element !== null) {
        element.removeEventListener("click", onClick);
      }
    };
  }, []);

  return myHookState;
}

export default useMyHook;
function App() {
  const buttonRef = useRef(null);
  const hookValue = useMyHook(buttonRef);
  const [forceUpdate, setForceUpdate] = useState(false);

  return (
    <div>
      <button onClick={() => setForceUpdate(prevState => !prevState)}>
        Update Component
      </button>
      <button ref={buttonRef}>Update Hook</button>
      {"This is hook returned value: " + hookValue}
    </div>
  );
}

解决方案非常简单,您只需要将ref传递给自定义挂钩,而不是
ref.current
,因为当ref被分配给DOM时,ref.current在其原始引用处发生变异,并且自定义挂钩中的useEffect在第一次渲染后被触发,因此
按钮ref.current
将引用DOM节点

使用myhook.js

function App() {
  const buttonRef = useRef(null);
  const hookValue = useMyHook(buttonRef.current);
  const [forceUpdate, setForceUpdate] = useState(false);

  return (
    <div>
      <button onClick={() => setForceUpdate(prevState => !prevState)}>
        Update Component
      </button>
      <button ref={buttonRef}>Update Hook</button>
      {"This is hook returned value: " + hookValue}
    </div>
  );
}
import { useEffect, useState } from "react";

function useMyHook(refEl) {
  const [myHookState, setMyHookState] = useState(0);

  console.log("Inside useMyhook...");
  console.log("This is the element received: ", refEl);

  useEffect(() => {
    const element = refEl.current;
    console.log("Inside useMyhook useEffect...");

    function onClick() {
      console.log("click");
      setMyHookState(prevState => prevState + 1);
    }
    console.log(element);
    if (element !== null) {
      element.addEventListener("click", onClick);
    }
    return () => {
      console.log("Inside useMyhook useEffect return...");
      if (element !== null) {
        element.removeEventListener("click", onClick);
      }
    };
  }, []);

  return myHookState;
}

export default useMyHook;
function App() {
  const buttonRef = useRef(null);
  const hookValue = useMyHook(buttonRef);
  const [forceUpdate, setForceUpdate] = useState(false);

  return (
    <div>
      <button onClick={() => setForceUpdate(prevState => !prevState)}>
        Update Component
      </button>
      <button ref={buttonRef}>Update Hook</button>
      {"This is hook returned value: " + hookValue}
    </div>
  );
}

index.js

function App() {
  const buttonRef = useRef(null);
  const hookValue = useMyHook(buttonRef.current);
  const [forceUpdate, setForceUpdate] = useState(false);

  return (
    <div>
      <button onClick={() => setForceUpdate(prevState => !prevState)}>
        Update Component
      </button>
      <button ref={buttonRef}>Update Hook</button>
      {"This is hook returned value: " + hookValue}
    </div>
  );
}
import { useEffect, useState } from "react";

function useMyHook(refEl) {
  const [myHookState, setMyHookState] = useState(0);

  console.log("Inside useMyhook...");
  console.log("This is the element received: ", refEl);

  useEffect(() => {
    const element = refEl.current;
    console.log("Inside useMyhook useEffect...");

    function onClick() {
      console.log("click");
      setMyHookState(prevState => prevState + 1);
    }
    console.log(element);
    if (element !== null) {
      element.addEventListener("click", onClick);
    }
    return () => {
      console.log("Inside useMyhook useEffect return...");
      if (element !== null) {
        element.removeEventListener("click", onClick);
      }
    };
  }, []);

  return myHookState;
}

export default useMyHook;
function App() {
  const buttonRef = useRef(null);
  const hookValue = useMyHook(buttonRef);
  const [forceUpdate, setForceUpdate] = useState(false);

  return (
    <div>
      <button onClick={() => setForceUpdate(prevState => !prevState)}>
        Update Component
      </button>
      <button ref={buttonRef}>Update Hook</button>
      {"This is hook returned value: " + hookValue}
    </div>
  );
}
函数应用程序(){
const buttonRef=useRef(null);
const hookValue=useMyHook(buttonRef);
const[forceUpdate,setForceUpdate]=useState(false);
返回(
setForceUpdate(prevState=>!prevState)}>
更新组件
更新挂钩
{“这是hook返回的值:“+hookValue}”
);
}

就这样!非常感谢。你能解释一下为什么在钩子中需要if(element!==null){
测试吗?