Skip to content
This repository has been archived by the owner on Jan 16, 2023. It is now read-only.

Commit

Permalink
feat(makeKeyProp): allow custom function for React key prop generation
Browse files Browse the repository at this point in the history
  • Loading branch information
anthony-dandrea committed May 12, 2021
1 parent 36d72f1 commit 63feb8a
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 25 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,17 @@ const decorators = {
<Treebeard data={...} decorators={decorators}/>
```

#### makeKeyProp
Optional prop to generate your own [React key props](https://reactjs.org/docs/lists-and-keys.html). Function that takes the node as the only param. Example:
```jsx
<Treebeard
data={data}
onToggle={this.onToggle}
onSelect={this.onSelect}
makeKeyProp={(node) => node.yourUniqueId}
/>
```

### Data Attributes

```javascript
Expand Down
5 changes: 5 additions & 0 deletions __tests__/Treebeard.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,9 @@ describe('<Treebeard/>', () => {
const wrapper = renderComponent();
expect(wrapper).toMatchSnapshot();
});
it('should handle custom makeKeyProp', () => {
const wrapper = renderComponent({ makeKeyProp: (node) => node.sha });
const firstNodeKey = wrapper.find('TreeNode').first().key();
expect(firstNodeKey).toBe('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08');
});
});
19 changes: 19 additions & 0 deletions __tests__/__snapshots__/Treebeard.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -46,76 +46,95 @@ exports[`<Treebeard/> should match default snapshot 1`] = `
}
}
key="1"
makeKeyProp={[Function]}
node={
Object {
"children": Array [
Object {
"children": Array [
Object {
"name": "app.js",
"sha": "828270ffd0e8ee6f32eb2a83bc3da31f3a9ac73f4833de481f65337c0802a9aa",
},
Object {
"name": "data.js",
"sha": "3ae815b93875786c05cba19df444662a789640e83ab65f4b84e9c16474cb1ed0",
},
Object {
"name": "index.html",
"sha": "f82ec4ae606600a57396ca47e21e0f013bded8523dfaffee040eefa4ea815962",
},
Object {
"name": "styles.js",
"sha": "3ba988e33afe3c6e453fc86bf26813ad90e5fe2dd7f55527a8c1408f861bfeac",
},
Object {
"name": "webpack.config.js",
"sha": "017cbc93d594c0f410b0c4c86c6b160a421674ddf72ab10201a16646f02fcb9c",
},
],
"name": "example",
"sha": "f05bcd2dffa3e047ce58c0f1a1877dcbe4d868cf0eac58bc2f7f9ab805289b0b",
},
Object {
"children": Array [],
"loading": true,
"name": "node_modules",
"sha": "bd9d2e8d246bc323081327ef12d3d40e0fc09cc7d36ea05bc286ea74e47c3515",
},
Object {
"children": Array [
Object {
"children": Array [
Object {
"name": "decorators.js",
"sha": "cc37c52929a8f16cfbf7b1881119f963e5a332507fac7d7f4fa9a271ad58534e",
},
Object {
"name": "treebeard.js",
"sha": "177c1b4a2b85d1c2a15ed481dbcefd9a43a901d6efa05c41dbb7e1859d5547e2",
},
],
"name": "components",
},
Object {
"name": "index.js",
"sha": "cc02786ca507e473781c0c08a2738e921eaa49c061515598d0ef1dff3054ea7b",
},
],
"name": "src",
"sha": "da5bd1bf868d4b2a68ce84c5e13545523ddc58232fe59e74a3d8ccb9be9e6db6",
},
Object {
"children": Array [
Object {
"name": "animations.js",
"sha": "1fde2cd5a18a6bd17660167f0fe5296a2ea1275da38961632b5630abf9c7a85d",
},
Object {
"name": "default.js",
"sha": "a59dc347bb2eb8f5a51f3b7f65dd63580829bcdfee89d5331f9ff063438b6dbd",
},
],
"name": "themes",
"sha": "8c382185c33911dbc2e2a76094b73a02644635ed9de1e9995a8b06f96bdbae32",
},
Object {
"name": "gulpfile.js",
"sha": "f68fe2b19685fb03204cfb3a0c7e58c7698fa9abc595185e39028fbc6e0531e1",
},
Object {
"name": "index.js",
"sha": "08f982599837827c163a787c6ae0a5cf1b493829493c1f29d707a5026b28ed0e",
},
Object {
"name": "package.json",
"sha": "c31e4a244c319e43a03cd3fbfabd0c6d976567c5b79e8b06a218b2aae3637839",
},
],
"id": 1,
"name": "react-treebeard",
"sha": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
"toggled": true,
}
}
Expand Down
37 changes: 24 additions & 13 deletions __tests__/mocks/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,55 @@ export default {
name: 'react-treebeard',
id: 1,
toggled: true,
sha: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08',
children: [
{
name: 'example',
sha: 'f05bcd2dffa3e047ce58c0f1a1877dcbe4d868cf0eac58bc2f7f9ab805289b0b',
children: [
{ name: 'app.js' },
{ name: 'data.js' },
{ name: 'index.html' },
{ name: 'styles.js' },
{ name: 'webpack.config.js' }
{ name: 'app.js', sha: '828270ffd0e8ee6f32eb2a83bc3da31f3a9ac73f4833de481f65337c0802a9aa' },
{ name: 'data.js', sha: '3ae815b93875786c05cba19df444662a789640e83ab65f4b84e9c16474cb1ed0' },
{ name: 'index.html', sha: 'f82ec4ae606600a57396ca47e21e0f013bded8523dfaffee040eefa4ea815962' },
{ name: 'styles.js', sha: '3ba988e33afe3c6e453fc86bf26813ad90e5fe2dd7f55527a8c1408f861bfeac' },
{ name: 'webpack.config.js', sha: '017cbc93d594c0f410b0c4c86c6b160a421674ddf72ab10201a16646f02fcb9c' }
]
},
{
name: 'node_modules',
loading: true,
sha: 'bd9d2e8d246bc323081327ef12d3d40e0fc09cc7d36ea05bc286ea74e47c3515',
children: []
},
{
name: 'src',
sha: 'da5bd1bf868d4b2a68ce84c5e13545523ddc58232fe59e74a3d8ccb9be9e6db6',
children: [
{
name: 'components',
children: [
{ name: 'decorators.js' },
{ name: 'treebeard.js' }
{
name: 'decorators.js',
sha: 'cc37c52929a8f16cfbf7b1881119f963e5a332507fac7d7f4fa9a271ad58534e'
},
{
name: 'treebeard.js',
sha: '177c1b4a2b85d1c2a15ed481dbcefd9a43a901d6efa05c41dbb7e1859d5547e2'
}
]
},
{ name: 'index.js' }
{ name: 'index.js', sha: 'cc02786ca507e473781c0c08a2738e921eaa49c061515598d0ef1dff3054ea7b' }
]
},
{
name: 'themes',
sha: '8c382185c33911dbc2e2a76094b73a02644635ed9de1e9995a8b06f96bdbae32',
children: [
{ name: 'animations.js' },
{ name: 'default.js' }
{ name: 'animations.js', sha: '1fde2cd5a18a6bd17660167f0fe5296a2ea1275da38961632b5630abf9c7a85d' },
{ name: 'default.js', sha: 'a59dc347bb2eb8f5a51f3b7f65dd63580829bcdfee89d5331f9ff063438b6dbd' }
]
},
{ name: 'gulpfile.js' },
{ name: 'index.js' },
{ name: 'package.json' }
{ name: 'gulpfile.js', sha: 'f68fe2b19685fb03204cfb3a0c7e58c7698fa9abc595185e39028fbc6e0531e1' },
{ name: 'index.js', sha: '08f982599837827c163a787c6ae0a5cf1b493829493c1f29d707a5026b28ed0e' },
{ name: 'package.json', sha: 'c31e4a244c319e43a03cd3fbfabd0c6d976567c5b79e8b06a218b2aae3637839' }
]
};
10 changes: 10 additions & 0 deletions __tests__/utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {makeKeyProp} from '../src/util';

describe('makeKeyProp', () => {
it('should return id first', () => {
expect(makeKeyProp({id: 'uniqueId'})).toBe('uniqueId');
});
it('should return random string if no id is present', () => {
expect(typeof makeKeyProp({})).toBe('string');
});
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-treebeard",
"version": "3.2.4",
"version": "3.2.5",
"description": "React Tree View Component",
"main": "index.js",
"scripts": {
Expand Down
12 changes: 7 additions & 5 deletions src/components/TreeNode/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styled from '@emotion/styled';
import {isArray, isFunction} from 'lodash';

import defaultAnimations from '../../themes/animations';
import {randomString} from '../../util';
import {makeKeyProp} from '../../util';
import {Ul} from '../common';
import NodeHeader from '../NodeHeader';
import Drawer from './Drawer';
Expand Down Expand Up @@ -45,7 +45,7 @@ class TreeNode extends PureComponent {

renderChildren(decorators) {
const {
animations, decorators: propDecorators, node, style, onToggle, onSelect, customStyles
animations, decorators: propDecorators, node, style, onToggle, onSelect, customStyles, makeKeyProp
} = this.props;

if (node.loading) {
Expand All @@ -69,7 +69,7 @@ class TreeNode extends PureComponent {
style={style}
customStyles={customStyles}
decorators={propDecorators}
key={child.id || randomString()}
key={makeKeyProp(child)}
node={child}
/>
))}
Expand Down Expand Up @@ -113,11 +113,13 @@ TreeNode.propTypes = {
animations: PropTypes.oneOfType([
PropTypes.object,
PropTypes.bool
]).isRequired
]).isRequired,
makeKeyProp: PropTypes.func
};

TreeNode.defaultProps = {
customStyles: {}
customStyles: {},
makeKeyProp
};

export default TreeNode;
13 changes: 8 additions & 5 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import {castArray} from 'lodash';

import defaultTheme from '../themes/default';
import defaultAnimations from '../themes/animations';
import {randomString} from '../util';
import {makeKeyProp} from '../util';
import {Ul} from './common';
import defaultDecorators from './Decorators';
import TreeNode from './TreeNode';

const TreeBeard = ({
animations, decorators, data, onToggle, style, onSelect, customStyles
animations, decorators, data, onToggle, style, onSelect, customStyles, makeKeyProp
}) => (
<Ul style={{...defaultTheme.tree.base, ...style.tree.base}}>
{castArray(data).map(node => (
Expand All @@ -21,7 +21,8 @@ const TreeBeard = ({
animations={animations}
onSelect={onSelect}
customStyles={customStyles}
key={node.id || randomString()}
makeKeyProp={makeKeyProp}
key={makeKeyProp(node)}
style={{...defaultTheme.tree.node, ...style.tree.node}}
/>
))}
Expand All @@ -41,14 +42,16 @@ TreeBeard.propTypes = {
]),
onToggle: PropTypes.func,
onSelect: PropTypes.func,
decorators: PropTypes.object
decorators: PropTypes.object,
makeKeyProp: PropTypes.func
};

TreeBeard.defaultProps = {
style: defaultTheme,
animations: defaultAnimations,
decorators: defaultDecorators,
customStyles: {}
customStyles: {},
makeKeyProp
};

export default TreeBeard;
6 changes: 5 additions & 1 deletion src/util/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import makeKeyProp from './makeKeyProp';
import randomString from './randomString';

export {randomString};
export {
makeKeyProp,
randomString
};
5 changes: 5 additions & 0 deletions src/util/makeKeyProp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import randomString from './randomString';

const makeKeyProp = (node) => node.id || randomString();

export default makeKeyProp;

0 comments on commit 63feb8a

Please sign in to comment.