Array.join
is useful because it glues together an array of strings by a delimiter taking into account empty arrays and not padding the delimiter at either end of the output string.
I am making a React application and I would like find a similar native function, however, my array of React.ReactNode
elements is going to be mapped and rendered, so instead of joining the array with a delimiter and outputting a string, I just want to join the array with a string delimiter, but maintain the Array structure. Is there something already native to javascript/typescript/react that I can use to achieve the below psuedo-code?
let parts: React.ReactNode[] = [];
if (conditionA) {
parts.push(<div>Component One</div>);
}
if (conditionB) {
parts.push(<div>Component Two</div>);
}
parts = joinByDelimiterButKeepAsArray(parts, '|');
// I wants parts to now equal
// [<div>Component One</div>, '|', <div>Component Two</div>]
// if conditionA and conditionB are both true
return (
<>
{parts.map((part, i) => return (
<React.ReactFragment key={i}>{part}</React.ReactFragment>
))}
</>
)
CodePudding user response:
You could use reduce
without the initialValue argument:
a.reduce((acc, val) => [].concat(acc, delimiter, val));
This requires special care when a
is an empty array. If that needs to be supported, then:
a.length ? a.reduce((acc, val) => [].concat(acc, delimiter, val)) : a;
CodePudding user response:
Welp, kind of answered my own question. Currently, I use the following function to achieve this:
function joinByDelimiterButKeepAsArray<T>(a: T[], delimiter: T): T[] {
return a.flatMap((n, i) => (i 1 < a.length ? [n, delimiter] : [n]));
}
Example:
const parts: React.ReactNode[] = [];
parts.push(<div>Component One</div>);
console.log(joinByDelimiterButKeepAsArray(parts, '|'));
/// [{...}]
parts.push(<div>Component Two</div>);
console.log(joinByDelimiterButKeepAsArray(parts, '|'));
/// [{...}, '|', {...}]
parts.push(<div>Component Three</div>);
console.log(joinByDelimiterButKeepAsArray(parts, '|'));
/// [{...}, '|', {...}, '|', {...}]
CodePudding user response:
You could try this solution:
const parts = ['<div>Component One</div>', '<div>Component Two</div>'];
/**
* Add the delimiter between each item in the array.
*
* @param {any[]} array
* @param {string} delimiter
* @returns {any[]}
*/
const joinByDelimiterButKeepAsArray = (array, delimiter) => {
/**
* To prevent the function from crashing, we need to check if the array is an array.
*/
if (!Array.isArray(array) || array.length === 0) {
return [];
}
const [firstElement, ...rest] = array;
return rest.reduce((acc, curr) =>
acc.concat(delimiter, curr)
/**
* The initialValue is set to an array containing the first element of the array to
* prevent the edge case of an array of length 1. If we don't do this, it would result
* in an array of length 2 with the first element being the first element of the array
* and the second element being the delimiter.
*
* e.g. [onlyOneElement] -> [onlyOneElement, delimiter]
*/
, [firstElement]);
};
console.log(joinByDelimiterButKeepAsArray(parts, '|'));