如何在 React 中编写 useComponent 自定义钩子?

Posted

技术标签:

【中文标题】如何在 React 中编写 useComponent 自定义钩子?【英文标题】:How to write a useComponent custom hook in React? 【发布时间】:2021-12-30 20:52:04 【问题描述】:

我想创建一个自定义钩子useComponent,它返回一个JSX.Element,它将在其他地方呈现。

我试过这个:

import  useState from 'react';

const useComponent = () => 

  const [value, setValue] = useState('');

  const c = () => 
    return <>
    <p>Component</p>
    <input value=value onChane=(e) => setValue(e.target.value) />
    </>
  

  return 
    c,
    value,
  




export default function App() 

  const c: C = useComponent();

  return (
    <div className="App">
      <C />
    </div>
  );


但它不起作用。一旦我尝试输入输入,什么都没有发生。

我怎样才能做到这一点?

我知道做这样的事情可能是一种不好的做法,但我想要这样做的原因是能够打开一个全局对话框并将c 组件作为children 传递给&lt;Dialog /&gt; 组件所以我既可以在对话框主体内渲染c,也可以访问[value, setValue] 状态。所以我的用例是这样的:

[编辑]

我还用对话框添加了整个逻辑:

import  createContext, useContext, useState  from "react";

const Test = ( value, setValue ) => 
  return (
    <>
      <p>Component</p>
      <input value=value onChange=(e) => setValue(e.target.value) />
    </>
  );
;

const useComponent = () => 
  const [value, setValue] = useState("");

  return 
    element: <Test value=value setValue=setValue />,
    value
  ;
;

const DialogCTX = createContext();

export function DialogProvider(props) 
  
  const [component, setComponent] = useState(null);

  const ctx = 
    component,
    setComponent
  ;

  return (
    <DialogCTX.Provider value= ctx >
      props.children
    </DialogCTX.Provider>
  );


export const useDialog = () => 
  const 
    component,
    setComponent,
   = useContext(DialogCTX);

  return 
    component,
    setComponent,
  
;

const Dialog = () => 

  const  component  = useDialog();
  return <div>
    <p>Dialog</p>
    component
    </div>


const Setter = () => 
  const element, value = useComponent();
  const setComponent = useDialog();

  return <div>
    <p>Setter component</p>
    <p>value</p>
    <button onClick=() => setComponent(element)>Set</button>
    </div>

export default function App() 
  
  return <div className="App">
    <DialogProvider>
      <Setter />
      <Dialog />
    </DialogProvider>
  </div>;

【问题讨论】:

【参考方案1】:

正如你所说,你想返回一个JSX.Element,但实际上每次你的钩子运行时你都会返回一个新组件(一个新函数)。因此,如果您实际上在钩子之外声明您的组件并返回渲染的组件,您就可以实现您的目标。这是一个工作示例:

import  useState  from "react";

const Test = ( value, setValue ) => 
  return (
    <>
      <p>Component</p>
      <input value=value onChange=(e) => setValue(e.target.value) />
    </>
  );
;

const useComponent = () => 
  const [value, setValue] = useState("");

  return 
    element: <Test value=value setValue=setValue />,
    value
  ;
;

export default function App() 
  const  element  = useComponent();

  return <div className="App">element</div>;

【讨论】:

请看看我的编辑。您的解决方案似乎仅在子项在创建状态的组件内呈现时才有效。 @entropyfeverone 确实,否则您需要为您的输入创建某种全局状态(可能使用上下文),但我不确定它是否像您想要的那样可扩展。检查这个code sandbox 你能在 Skroutz 推荐我吗? :p 哈哈,我们其实没有推荐系统,但是目前有很多空缺,去吧!

以上是关于如何在 React 中编写 useComponent 自定义钩子?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 axios 拦截器中编写重定向而不在 React JS 中重新加载

如何编写依赖于 React 中 useState 钩子的条件渲染组件的测试?

如何使用 React、Jest 和 React-testing-library 为带有令牌的 api 调用编写单元测试?

如何在用 TypeScript (TSX) 编写的 React 应用程序中使用 Facebook Relay?

如何编写漂亮的React代码?

如何编写扩展功能组件的 ES6 类 React 组件?