-
-
Save granmoe/274c299b792b039deecfb619753ea32c to your computer and use it in GitHub Desktop.
This file is only here to provide the title of the gist |
import React from 'react' | |
import joinChildren from 'react-join-children' | |
import { Item, Separator } from 'justanexample' | |
export default class MyComponent extends React.Component { | |
render () { | |
return <div> | |
{ joinChildren(this.props.items, this.renderItem, this.renderSeparator) } | |
</div> | |
// with 3 items, joinChildren returns [<Item>, <Separator>, <Item>, <Separator>, <Item>] | |
} | |
renderItem = (item, index) => { | |
return <Item key={ index } className="item" /> | |
} | |
renderSeparator = key => { | |
return <Separator className="separator" key={ key } /> | |
} | |
} |
export default function (children, render, renderSeparator) { | |
return children.reduce((result, child, index) => { | |
if (index < children.length - 1) { | |
return result.concat([render(child, index), renderSeparator(index + '-separator')]) | |
} | |
return result.concat(render(child, index)) | |
}, []) | |
} |
The better function here is flatMap
(or chain
in Ramda). Unfortunately JS does not provide one (yet).
<p className="conceps inline list">
{flatMap((concept, i) =>
[concept, <span key={i} className="separator">•</span>]
, R.map(removeTags, lesson.concepts))}
</p>
generates something like
Function • Function type • Higher-order function • Partial application
P.S.
for Ramda it's R.addIndex(R.chain)
instead of flatMap
above.
Shameless plug for a similar module I just published: react-with-separator
const WithSeparator = require('react-with-separator')
const React = require('react')
const { render } = require('react-dom')
const Footer = ({ username }) => (
<WithSeparator separator=' | '>
(!username && (
<a href='/login'>Login</a>
))
(username && (
<a href='/logout'>Logout</a>
))
<a href='/help'>Help</a>
</WithSeparator>
)
render(<Footer username='linusu' \>)
could also be used as such, to match usage in first post:
export default class MyComponent extends React.Component {
render () {
return <WithSeparator separator={<Separator className="separator" />}>
{this.props.items.map((item, index) => this.renderItem(item, index))}
</WithSeparator >
// with 3 items, joinChildren returns [<Item>, <Separator>, <Item>, <Separator>, <Item>]
}
renderItem = (item, index) => {
return <Item key={ index } className="item" />
}
}
Simple approach to this will be using map()
:
import React from 'react'
export default class MyComponent extends React.Component {
render () {
return (
<div>
{
map(props.items, (item, index) => {
return (
<span>
{ !!index && ', '}
<Item key={ index } className="item" />
</span>
)
})
}
</div>
)
}
}
Thanks for the idea @dinzy17 that worked great!
Thanks :)
Thanks :)
Whoa...somehow I never got any notifications on this until yours, @zachwolf. Oh the mortifying feeling when you find out other human beings have looked at a random thing that you wrote two years ago :P My style has evolved since then, but I think the concept stands the test of time.
Anyhow...glad I could help?
been searching for this for an hour. thanks so much
had to find it using site:gist.github.com
So, some years have passed, and now we have React fragments, which don't add any extra nodes to the DOM, so we can simply do:
{things.map((thing, index) => (
<>
{index > 0 && <Separator />}
<Thing />
</>
))}
This is similar to @dinzy17's approach above, but it doesn't add an extra wrapper around each item (just for cases where you don't or can't add an extra wrapper).
@granmoe you need to assign a key prop to the fragments:
{list.map((item, index) => (
<React.Fragment key={item.id}>
{!!index && <Separator />}
<Item item={item} />
</React.Fragment>
))}
@granmoe you need to assign a key prop to the fragments:
{list.map((item, index) => ( <React.Fragment key={item.id}> {!!index && <Separator />} <Item item={item} /> </React.Fragment> ))}
Yep, good catch.
(This was just a hastily written example, but may as well not encourage poor practices 👍)
import React, { FunctionComponent, ReactNode } from 'react';
export const Separated: FunctionComponent<{ separator?: ReactNode }> = ({ children, separator = ' ' }) => {
return (
<>
{React.Children.toArray(children)
.reduce<ReactNode[]>((previousValue, currentValue) => {
return [...previousValue, currentValue, separator];
}, [])
.slice(0, -1)}
</>
);
};
Works perfectly, thanks!