Skip to content

Commit 81926f3

Browse files
authored
Remove UNSAFE methods from react-json-tree (#1288)
* Remove UNSAFE method from JSONTree * Bump peer dep * Fix types * Remove proptypes * Remove unused * shouldExpandNode => shouldExpandNodeInitially * Cleanup * Update usages * Tighten types * Create four-parrots-poke.md * Format * Fix inspector-monitor types * Fix log-monitor types * Fix rtk-query-monitor types * Fix type
1 parent 5f33eeb commit 81926f3

28 files changed

+418
-650
lines changed

.changeset/four-parrots-poke.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'react-json-tree': major
3+
---
4+
5+
Remove UNSAFE method from react-json-tree
6+
7+
- Replace `shouldExpandNode` with `shouldExpandNodeInitially`. This function is now only called when a node in the tree is first rendered, when before it would update the expanded state of the node if the results of calling `shouldExpandNode` changed between renders. There is no way to replicate the old behavior exactly, but the new behavior is the intended behavior for the use cases within Redux DevTools. Please open an issue if you need a way to programatically control the expanded state of nodes.
8+
- Bump the minimum React version from `16.3.0` to `16.8.0` so that `react-json-tree` can use hooks.
9+
- Tightened TypeScript prop types to use `unknown` instead of `any` where possible and make the key path array `readonly`.

packages/react-json-tree/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ Their full signatures are:
139139

140140
#### More Options
141141

142-
- `shouldExpandNode: function(keyPath, data, level)` - determines if node should be expanded (root is expanded by default)
142+
- `shouldExpandNodeInitially: function(keyPath, data, level)` - determines if node should be expanded when it first renders (root is expanded by default)
143143
- `hideRoot: boolean` - if `true`, the root node is hidden.
144144
- `sortObjectKeys: boolean | function(a, b)` - sorts object keys with compare function (optional). Isn't applied to iterable maps like `Immutable.Map`.
145145
- `postprocessValue: function(value)` - maps `value` to a new `value`

packages/react-json-tree/examples/src/App.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ const App = () => (
178178
<span role="img" aria-label="mellow">
179179
😐
180180
</span>{' '}
181-
{raw}{' '}
181+
{raw as string}{' '}
182182
<span role="img" aria-label="mellow">
183183
😐
184184
</span>
@@ -194,7 +194,11 @@ const App = () => (
194194
</div>
195195
<p>Collapsed root node</p>
196196
<div>
197-
<JSONTree data={data} theme={theme} shouldExpandNode={() => false} />
197+
<JSONTree
198+
data={data}
199+
theme={theme}
200+
shouldExpandNodeInitially={() => false}
201+
/>
198202
</div>
199203
</div>
200204
);

packages/react-json-tree/package.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@
4747
"dependencies": {
4848
"@babel/runtime": "^7.20.6",
4949
"@types/lodash": "^4.14.191",
50-
"@types/prop-types": "^15.7.5",
51-
"prop-types": "^15.8.1",
5250
"react-base16-styling": "^0.9.1"
5351
},
5452
"devDependencies": {
@@ -85,7 +83,7 @@
8583
"typescript": "~4.9.4"
8684
},
8785
"peerDependencies": {
88-
"@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0",
89-
"react": "^16.3.0 || ^17.0.0 || ^18.0.0"
86+
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
87+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
9088
}
9189
}
Lines changed: 28 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,39 @@
1-
import React from 'react';
2-
import PropTypes from 'prop-types';
1+
import React, { useCallback, useState } from 'react';
32
import JSONArrow from './JSONArrow';
4-
import { CircularPropsPassedThroughItemRange } from './types';
3+
import type { CircularCache, CommonInternalProps } from './types';
54

6-
interface Props extends CircularPropsPassedThroughItemRange {
7-
data: any;
5+
interface Props extends CommonInternalProps {
6+
data: unknown;
87
nodeType: string;
98
from: number;
109
to: number;
1110
renderChildNodes: (props: Props, from: number, to: number) => React.ReactNode;
11+
circularCache: CircularCache;
12+
level: number;
1213
}
1314

14-
interface State {
15-
expanded: boolean;
16-
}
17-
18-
export default class ItemRange extends React.Component<Props, State> {
19-
static propTypes = {
20-
styling: PropTypes.func.isRequired,
21-
from: PropTypes.number.isRequired,
22-
to: PropTypes.number.isRequired,
23-
renderChildNodes: PropTypes.func.isRequired,
24-
nodeType: PropTypes.string.isRequired,
25-
};
26-
27-
constructor(props: Props) {
28-
super(props);
29-
this.state = { expanded: false };
30-
}
31-
32-
render() {
33-
const { styling, from, to, renderChildNodes, nodeType } = this.props;
15+
export default function ItemRange(props: Props) {
16+
const { styling, from, to, renderChildNodes, nodeType } = props;
3417

35-
return this.state.expanded ? (
36-
<div {...styling('itemRange', this.state.expanded)}>
37-
{renderChildNodes(this.props, from, to)}
38-
</div>
39-
) : (
40-
<div
41-
{...styling('itemRange', this.state.expanded)}
42-
onClick={this.handleClick}
43-
>
44-
<JSONArrow
45-
nodeType={nodeType}
46-
styling={styling}
47-
expanded={false}
48-
onClick={this.handleClick}
49-
arrowStyle="double"
50-
/>
51-
{`${from} ... ${to}`}
52-
</div>
53-
);
54-
}
18+
const [expanded, setExpanded] = useState<boolean>(false);
19+
const handleClick = useCallback(() => {
20+
setExpanded(!expanded);
21+
}, [expanded]);
5522

56-
handleClick = () => {
57-
this.setState({ expanded: !this.state.expanded });
58-
};
23+
return expanded ? (
24+
<div {...styling('itemRange', expanded)}>
25+
{renderChildNodes(props, from, to)}
26+
</div>
27+
) : (
28+
<div {...styling('itemRange', expanded)} onClick={handleClick}>
29+
<JSONArrow
30+
nodeType={nodeType}
31+
styling={styling}
32+
expanded={false}
33+
onClick={handleClick}
34+
arrowStyle="double"
35+
/>
36+
{`${from} ... ${to}`}
37+
</div>
38+
);
5939
}
Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,30 @@
11
import React from 'react';
2-
import PropTypes from 'prop-types';
32
import JSONNestedNode from './JSONNestedNode';
4-
import { CircularPropsPassedThroughJSONNode } from './types';
3+
import type { CommonInternalProps } from './types';
54

65
// Returns the "n Items" string for this node,
76
// generating and caching it if it hasn't been created yet.
8-
function createItemString(data: any) {
7+
function createItemString(data: unknown) {
98
return `${(data as unknown[]).length} ${
109
(data as unknown[]).length !== 1 ? 'items' : 'item'
1110
}`;
1211
}
1312

14-
interface Props extends CircularPropsPassedThroughJSONNode {
15-
data: any;
13+
interface Props extends CommonInternalProps {
14+
data: unknown;
1615
nodeType: string;
1716
}
1817

1918
// Configures <JSONNestedNode> to render an Array
20-
const JSONArrayNode: React.FunctionComponent<Props> = ({ data, ...props }) => (
21-
<JSONNestedNode
22-
{...props}
23-
data={data}
24-
nodeType="Array"
25-
nodeTypeIndicator="[]"
26-
createItemString={createItemString}
27-
expandable={data.length > 0}
28-
/>
29-
);
30-
31-
JSONArrayNode.propTypes = {
32-
data: PropTypes.array,
33-
};
34-
35-
export default JSONArrayNode;
19+
export default function JSONArrayNode({ data, ...props }: Props) {
20+
return (
21+
<JSONNestedNode
22+
{...props}
23+
data={data}
24+
nodeType="Array"
25+
nodeTypeIndicator="[]"
26+
createItemString={createItemString}
27+
expandable={(data as unknown[]).length > 0}
28+
/>
29+
);
30+
}
Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React from 'react';
2-
import PropTypes from 'prop-types';
3-
import { StylingFunction } from 'react-base16-styling';
2+
import type { StylingFunction } from 'react-base16-styling';
43

54
interface Props {
65
styling: StylingFunction;
@@ -10,33 +9,21 @@ interface Props {
109
onClick: React.MouseEventHandler<HTMLDivElement>;
1110
}
1211

13-
const JSONArrow: React.FunctionComponent<Props> = ({
12+
export default function JSONArrow({
1413
styling,
15-
arrowStyle,
14+
arrowStyle = 'single',
1615
expanded,
1716
nodeType,
1817
onClick,
19-
}) => (
20-
<div {...styling('arrowContainer', arrowStyle)} onClick={onClick}>
21-
<div {...styling(['arrow', 'arrowSign'], nodeType, expanded, arrowStyle)}>
22-
{'\u25B6'}
23-
{arrowStyle === 'double' && (
24-
<div {...styling(['arrowSign', 'arrowSignInner'])}>{'\u25B6'}</div>
25-
)}
18+
}: Props) {
19+
return (
20+
<div {...styling('arrowContainer', arrowStyle)} onClick={onClick}>
21+
<div {...styling(['arrow', 'arrowSign'], nodeType, expanded, arrowStyle)}>
22+
{'\u25B6'}
23+
{arrowStyle === 'double' && (
24+
<div {...styling(['arrowSign', 'arrowSignInner'])}>{'\u25B6'}</div>
25+
)}
26+
</div>
2627
</div>
27-
</div>
28-
);
29-
30-
JSONArrow.propTypes = {
31-
styling: PropTypes.func.isRequired,
32-
arrowStyle: PropTypes.oneOf(['single', 'double']),
33-
expanded: PropTypes.bool.isRequired,
34-
nodeType: PropTypes.string.isRequired,
35-
onClick: PropTypes.func.isRequired,
36-
};
37-
38-
JSONArrow.defaultProps = {
39-
arrowStyle: 'single',
40-
};
41-
42-
export default JSONArrow;
28+
);
29+
}

packages/react-json-tree/src/JSONIterableNode.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import JSONNestedNode from './JSONNestedNode';
3-
import { CircularPropsPassedThroughJSONNode } from './types';
3+
import type { CommonInternalProps } from './types';
44

55
// Returns the "n Items" string for this node,
66
// generating and caching it if it hasn't been created yet.
@@ -22,21 +22,20 @@ function createItemString(data: any, limit: number) {
2222
return `${hasMore ? '>' : ''}${count} ${count !== 1 ? 'entries' : 'entry'}`;
2323
}
2424

25-
interface Props extends CircularPropsPassedThroughJSONNode {
26-
data: any;
25+
interface Props extends CommonInternalProps {
26+
data: unknown;
2727
nodeType: string;
2828
}
2929

3030
// Configures <JSONNestedNode> to render an iterable
31-
const JSONIterableNode: React.FunctionComponent<Props> = ({ ...props }) => {
31+
export default function JSONIterableNode(props: Props) {
3232
return (
3333
<JSONNestedNode
3434
{...props}
3535
nodeType="Iterable"
3636
nodeTypeIndicator="()"
3737
createItemString={createItemString}
38+
expandable
3839
/>
3940
);
40-
};
41-
42-
export default JSONIterableNode;
41+
}

0 commit comments

Comments
 (0)