Reputation: 1168
Is this an anti-pattern?
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>
);
}
What's the difference between rendering items like that, as compared to making an Item component inside Todo, such as this:
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>
);
}
EDIT:
What about creating components/render functions locally, that are called once?
export function SomeForm(props) {
const renderButton = (isComplete) => (
isComplete
? <button>Submit</button>
: <button disabled>Please complete</button>
);
return (
<form>
<input />
{renderButton(props.isDone)}
</form>
);
}
Upvotes: 6
Views: 3205
Reputation: 53874
Beforehand lets fix the examples into a valid code:
// #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>
);
}
Back to the question, Yes those are anti-patterns.
In both examples, you will rerender the item even though there wasn't any visual change.
The reason for it because on every render, you recreate both function (renderItem
) and function component (Item
).
Instead, you want to let React do the Reconciliation process, for it you need render a static tree as much as possible.
The easiest solution is just move the function/function component, to the outer scope or inlining the logic into the tree itself.
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>
);
}
What's the difference between rendering items like that
renderItem
is just a function returning JSX, Item
is a React component, therefore its state is registered to the React tree ("just a function" can't hold its own state).
Upvotes: 14