微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

有没有一种在回调或渲染道具中使用 React 钩子的好方法?

如何解决有没有一种在回调或渲染道具中使用 React 钩子的好方法?

我经常发现自己创建或使用组件,其中回调用于创建组件树的一部分,如以下两个简化示例:

// Example 1: Render an array of components
const ExampleComponent1 = () => (
    <ul>
        {items.map((item) => <li key={item.id} style={{ paddingTop: item.paddingTop }}>{item.label}</li>)}
    </ul>
);

// Example 2: Use render props
const ExampleComponent2 = () => (
    <Dialog
        renderHeader={useCallback((dialogCtx) => 'Header',[])}
        renderBody={useCallback((dialogCtx) => <button onClick={() => dialogCtx.closeDialog(null)}>Test</button>,[])}
    />
);

如您所见,两种情况下的回调结果都取决于回调参数。为了避免在每次渲染时创建新的 style 对象(在示例 1 中)和新的 onClick 函数(在示例 2 中),我应该将它们包装在 useMemo/{ {1}},但这在这里是不可能的,因为它们是在回调内部创建的,而不是在组件的根级别上创建的。

我所知道的解决此问题的唯一方法是为每个回调创建指定的组件:

useCallback

您已经在这个简化的示例中看到了如何以这种方式拆分应用程序会创建大量额外的代码并使应用程序更难阅读。在更复杂的场景中,父组件的大量 props 需要在子组件中重用,子组件会变得更加庞大,特别是当还需要定义 prop 类型时。

在我看来,这两个示例都是相当常见的用例,因为回调是在 React 中从数组生成组件列表的唯一方法,而渲染道具是更复杂组件中的常见模式。我想知道:

  • 有什么办法可以在不将回调结果拆分为单独的组件的情况下编写上述示例?例如直接在回调中使用钩子的一些方法
  • 是否有其他模式可以将数组映射到不依赖回调的组件列表,以便可以使用钩子?
  • 是否有替代模式来渲染 props 以便更轻松地使用钩子?

更新:为了清楚起见,我正在寻找一种编程模式,而不是上面简化示例代码中的具体问题。

解决方法

我不明白示例 1 有什么问题。

const ExampleComponent1 = () => (
    <ul>
        {items.map((item) => <li key={item.id} style={{ paddingTop: item.paddingTop }}>{item.label}</li>)}
    </ul>
);

这在 React 中完全没问题。在您看到 style 道具导致性能问题之前,您不应尝试对其进行优化。

带有钩子的版本,以防你真的需要它:

const ExampleComponent1Item = ({ item }) => {
  const style = useMemo(() => ({ paddingTop: item.paddingTop }),[item.paddingTop]);

  return (<li style={style}>{item.label}</li>);
};

const ExampleComponent1 = () => (
    <ul>
        {items.map((item) => <ExampleComponent1Item key={item.id} item={item}/>)}
    </ul>
);

同样适用于示例 2:

const ExampleComponent2 = () => {
  const renderHeader = useCallback((dialogCtx) => 'Header',[]);
  const renderBody = useCallback((dialogCtx) => <button onClick={() => dialogCtx.closeDialog(null)}>Test</button>,[]);

  return (<Dialog renderHeader={renderHeader} renderBody=renderBody}/>);
};

如果您想避免每次调用 onClick 时都重新创建 renderBody 函数,您可以这样做:

const ExampleComponent2Body = {( dialogCtx }) => {
  const onClick = useCallback(() => dialogCtx.closeDialog(null),[dialogCtx.closeDialog]);

  return (<button onClick={onClick}>Test</button>);
};

const ExampleComponent2 = () => {
  const renderHeader = useCallback((dialogCtx) => 'Header',[]);
  const renderBody = useCallback((dialogCtx) => <ExampleComponent2Body dialogCtx={dialogCtx}/>,[]);

  return (<Dialog renderHeader={renderHeader} renderBody=renderBody}/>);
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?