自定义钩子可以确定哪个组件调用它吗?

时间:2021-03-19 19:19:35

标签: reactjs react-hooks

我制作了一个自定义钩子,将数据注册到由使用它的组件键控的存储中,然后在卸载组件时从存储中删除数据。基本都是这样

const [id] = useState(Math.random());

const setData = useCallback((data) => {
  if(data) {
    setRegistrations({
      ...registrations,
      [id]: data
    });
  } else {
    const {[id]: _, ...nextRegistrations} = registrations;
    setRegistrations(nextRegistrations);
  }
}, [id]);

useEffect(() => {
  // update the registration if the data changed
  setData(data); 
}, [data, setData]);

useEffect(() => {
  // remove the registration on unmount
  setData();
}, []);

我正在使用 Math.random() 为每个使用我的钩子的组件生成一个唯一的 id,这工作正常,但我希望有一种方法可以找出使用我的钩子的组件的名称.如果我能看到哪个数据由哪个组件注册,那么调试我的应用程序状态会更容易,但我只需要查看一个随机小数。

现在我的商店看起来像这样

{
  '0.5694216823063629': { ... }
  '0.002760497537984463': { ... }
}

如果我能做这样的事情,我更愿意

{
  'MyComponent-1': { ... }
  'MyComponent-2': { ... }
  'MyOtherComponent-1': { ... }
}

是的,我知道我可以让组件传入一个键,但这没有抓住重点。我希望 API 保持纯净而不污染它,以便调试更容易。

有没有办法找出哪个组件使用了我的钩子?

1 个答案:

答案 0 :(得分:2)

函数和参数对象具有不推荐使用的属性,允许他们查看是谁调用了它们 - Function.callerarguments.callee。但是,它们都在严格模式下被阻止。

你可以在抛出错误时从堆栈中获取调用者的名字,但这很丑陋,你应该只在开发模式下使用它。这仅适用于函数组件,但由于您在钩子中使用它,所以不会有问题。

示例(取自此 article):

// taken from https://devimalplanet.com/javascript-how-to-get-the-caller-parent-functions-name
function whoIsMyDaddy() {
  try {
    throw new Error();
  } catch (e) {
    // matches this function, the caller and the parent
    const allMatches = e.stack.match(/(\w+)@|at (\w+) \(/g);
    // match parent function name
    const parentMatches = allMatches[2].match(/(\w+)@|at (\w+) \(/);
    // return only name
    return parentMatches[1] || parentMatches[2];
  }
}

const useDemo = () => {
  const daddy = whoIsMyDaddy()
  React.useEffect(() => console.log(daddy))
}

const ComponentX = () => {
  useDemo()
  
  return 'X'
}

const ComponentY = () => {
  useDemo()
  
  return 'Y'
}

ReactDOM.render(
  <div>
    <ComponentX />
    <ComponentY />
  </div>,
  root
)
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

<div id="root"></div>

注意: 使用 Math.random() 作为 id 不是一个好主意,因为 Math.random() 不是那么随机 - 请参阅此 answer。您可以使用 Crypto.getRandomValues()(如果支持)或外部 uuid 库。