Зависит от задачи и того, что у вас внутри компонента Layout.
renderAfter нужно вызывать так: after={renderAfter()} либо внутри компонента так сделать.
Функцию делать не рекомендую, т.к. при каждом ререндере она будет пересозаваться.
Я сам всегда использую вариант объявления констант в компоненте, чтобы минимизировать размер рендера.
В useMemo тоже смысла тут не вижу. Его стоит использовать для хранения результата тяжелых вычислений для минимизации нагрузки на браузер.
Пример
import { Divider } from '@mui/material'
import React, { FC, forwardRef } from 'react'
import { Typography, Button, Tooltip, Icon, Link } from '../../atoms'
import { Dropdown } from '../../molecules'
import { theme } from '../../theme'
import {
SSectionBoxWrapper,
SSectionBoxHeader,
SSectionBoxContent,
SSectionBoxHeaderSection,
SSectionBoxDropdown,
SSectionBoxSubtitle,
SSectionBoxTitle,
SSectionBoxTooltipIconWrapper,
SSectionBoxSearchWrapper,
SSectionBoxSearchInput,
SSectionBoxSearchIcon,
} from './styles'
import { SectionBoxProps } from './types'
export const SectionBox: FC<SectionBoxProps> = forwardRef(({
leadIcon,
title,
subTitle,
tooltip,
actionButtons,
action,
link,
selectOptions,
searchOptions,
children,
noChildrenText = 'Nothing here',
withBackground,
customComponent,
withPaddings = true,
showHeaderDivider = false,
...props
}, ref) => {
const hasLeftSide = Boolean(leadIcon || title || subTitle || tooltip || actionButtons)
const hasRightSide = Boolean(action || link || selectOptions || searchOptions || customComponent)
const dropdownNode = leadIcon && <SSectionBoxDropdown {...leadIcon} />
const titleNode = title && <SSectionBoxTitle>{title}</SSectionBoxTitle>
const subtitleNode = subTitle && <SSectionBoxSubtitle>{subTitle}</SSectionBoxSubtitle>
const tooltipNode = tooltip && (
<Tooltip placement="top" {...tooltip}>
<SSectionBoxTooltipIconWrapper>
<Icon name="InfoOutlined" fontSize="small" />
</SSectionBoxTooltipIconWrapper>
</Tooltip>
)
const actionsNode =
actionButtons &&
actionButtons.length > 0 &&
actionButtons.map((item, index) => (
<Button {...item} key={index}>
{item.label}
</Button>
))
const actionNode = action && <Button {...action}>{action.label}</Button>
const linkNode = link && <Link {...link}>{link.label}</Link>
const noChildrenNode = (
<Typography align="center" fontStyle="italic" color={theme.palette.grey[500]} fontWeight={400}>
{noChildrenText}
</Typography>
)
const selectOptionsNode = selectOptions && <Dropdown {...selectOptions} />
const searchNode = searchOptions && (
<SSectionBoxSearchWrapper>
<SSectionBoxSearchIcon name="Search" />
<SSectionBoxSearchInput label="Search" variant="standard" autoComplete="off" {...searchOptions} />
</SSectionBoxSearchWrapper>
)
const header = (hasLeftSide || hasRightSide) && (
<SSectionBoxHeader $hasLeftSide={hasLeftSide} $hasRightSide={hasRightSide}>
<SSectionBoxHeaderSection>
{actionsNode}
{dropdownNode}
{titleNode}
{subtitleNode}
{tooltipNode}
</SSectionBoxHeaderSection>
<SSectionBoxHeaderSection>
{actionNode}
{linkNode}
{searchNode}
{selectOptionsNode}
{customComponent}
</SSectionBoxHeaderSection>
</SSectionBoxHeader>
)
return (
<SSectionBoxWrapper
$withBackground={withBackground}
$withPaddings={withPaddings}
ref={ref}
{...props}
>
{header}
{showHeaderDivider && <Divider />}
<SSectionBoxContent>{children ? React.Children.map(children, item => item) : noChildrenNode}</SSectionBoxContent>
</SSectionBoxWrapper>
)
})
export default SectionBox