呈现 JSX 的函数与在另一个组件中声明组件的函数有啥区别?

Posted

技术标签:

【中文标题】呈现 JSX 的函数与在另一个组件中声明组件的函数有啥区别?【英文标题】:What's the difference between functions that render JSX vs. declaring components inside another component?呈现 JSX 的函数与在另一个组件中声明组件的函数有什么区别? 【发布时间】:2021-07-30 22:38:54 【问题描述】:

这是一种反模式吗?

export function Todo() 
    ...

    const renderItem = (item) => (
        item.done
            ? <strike>item.text</strike>
            : <span>item.text</span>
    );

    return (
        <ul>
            items.map((item) => <li>renderItems(item)</li>)
        </ul>
    );

与在 Todo 中制作 Item 组件相比,这样渲染项目有什么区别,例如:

export function Todo() 
    ...

    const Item = (props) => (
        props.item.done
            ? <strike>item.text</strike>
            : <span>item.text</span>
    );

    return (
        <ul>
            items.map((item) => <li><Item item=item /></li>)
        </ul>
    );

编辑:

如何在本地创建组件/渲染函数,调用一次?

export function SomeForm(props) 
    const renderButton = (isComplete) => (
        isComplete
            ? <button>Submit</button>
            : <button disabled>Please complete</button>
    );

    return (
        <form>
            <input />
            renderButton(props.isDone)
        </form>
    );

【问题讨论】:

Losing state between renders if component is defined in another component 这能回答你的问题吗? Is it an anti-pattern to define a function component inside the render() function? 【参考方案1】:

事先让我们将示例修复为有效代码:

// #1
export function Todo(items) 
  const renderItem = (item) =>
    item.done ? <strike>item.text</strike> : <span>item.text</span>;

  return (
    <ul>
      items.map((item) => (
        <li key=item.id>renderItems(item)</li>
      ))
    </ul>
  );


// #2
export function Todo(items) 
  const Item = (props) =>
    props.item.done ? <strike>item.text</strike> : <span>item.text</span>;

  return (
    <ul>
      items.map((item) => (
        <li key=item.id>
          <Item item=item />
        </li>
      ))
    </ul>
  );

回到问题,是的这些都是反模式。

为什么它是反模式?

在这两个示例中,即使没有任何视觉变化,您也会重新渲染项目。

原因是因为在每次渲染时,您都重新创建了函数 (renderItem) 和函数组件 (Item)。

你想要什么

相反,您想让 React 执行 Reconciliation 进程,因为您需要尽可能多地渲染静态树。

最简单的解决方案是将函数/函数组件移动到外部范围或将逻辑内联到树本身。

const renderItem = (item) => (...)
const Item = (props) => (...)

export function Todo( items ) 
  return (
    <ul>
      items.map((item) => (
        <li key=item.id>
          (item.done ? <strike>item.text</strike>:<span>item.text</span>)
        </li>
      ))
    </ul>
  );


这样渲染项目有什么区别

renderItem 只是一个返回 JSX 的函数,Item 是一个 React 组件,因此它的状态被注册到 React 树(“只是一个函数”不能保持它自己的状态)。

【讨论】:

感谢您阐明“只是一个函数”和一个反应组件之间的区别!我知道这在渲染各种列表时效率特别低,但是如果我只渲染一次会怎样。那么创建“渲染”功能或本地组件仍然是反模式吗?我在编辑中添加了(一个相当做作的)示例。 您的编辑是相同的示例,仍然是反模式

以上是关于呈现 JSX 的函数与在另一个组件中声明组件的函数有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

渲染在另一个组件的渲染函数中声明的组件不包括对 REACT 17 中 componentDidMount 方法的更改

与在另一个窗口中打开的组件交互

React/JSX 动态组件名称

React/JSX 动态组件名称

如何在 JSX 的三元运算符中调用两个函数?

在另一个计算属性上调用 getter 不是测试中的函数