Skip to content

Commit 1d79bee

Browse files
Convert NullField and NumberField to functional components (rjsf-team#3030)
- Added or updated `jest.config.js` files to all themes that add `moduleNameMapper` for `react` and `react-dom` to avoid hooks issues - Updated `NullField` and `NumberField` to be stateless functional components
1 parent ee9b46a commit 1d79bee

File tree

10 files changed

+68
-63
lines changed

10 files changed

+68
-63
lines changed

packages/antd/jest.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
moduleNameMapper: {
3+
"^react$": "<rootDir>/node_modules/react",
4+
"^react-dom$": "<rootDir>/node_modules/react-dom",
5+
},
6+
};

packages/bootstrap-4/jest.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
moduleNameMapper: {
3+
"^react$": "<rootDir>/node_modules/react",
4+
"^react-dom$": "<rootDir>/node_modules/react-dom",
5+
},
6+
};

packages/chakra-ui/jest.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
module.exports = {
2+
moduleNameMapper: {
3+
"^react$": "<rootDir>/node_modules/react",
4+
"^react-dom$": "<rootDir>/node_modules/react-dom",
5+
},
26
snapshotSerializers: ["@emotion/jest/serializer"],
37
testEnvironment: "jsdom",
48
testEnvironmentOptions: {

packages/core/jest.config.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
module.exports = {
2-
verbose: true,
3-
setupFilesAfterEnv: ["./test/setup-jsdom.js"],
4-
testMatch: ["**/test/**/*_test.js"]
5-
};
2+
moduleNameMapper: {
3+
"^react$": "<rootDir>/node_modules/react",
4+
"^react-dom$": "<rootDir>/node_modules/react-dom",
5+
},
6+
verbose: true,
7+
setupFilesAfterEnv: ["./test/setup-jsdom.js"],
8+
testMatch: ["**/test/**/*_test.js"]
9+
};
Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,20 @@
1-
import { Component } from "react";
1+
import { useEffect } from "react";
22
import { FieldProps } from "@rjsf/utils";
33

44
/** The `NullField` component is used to render a field in the schema is null. It also ensures that the `formData` is
55
* also set to null if it has no value.
66
*
77
* @param props - The `FieldProps` for this template
88
*/
9-
class NullField<T = any, F = any> extends Component<FieldProps<T, F>> {
10-
/** React lifecycle method is called after a component mounts. Will convert an undefined formData to a null via the
11-
* onChange callback
12-
*/
13-
componentDidMount() {
14-
const { formData, onChange } = this.props;
9+
function NullField<T = any, F = any>(props: FieldProps<T, F>) {
10+
const { formData, onChange } = props;
11+
useEffect(() => {
1512
if (formData === undefined) {
1613
onChange(null as unknown as T);
1714
}
18-
}
15+
}, []);
1916

20-
/** Renders null for the null field
21-
*/
22-
render() {
23-
return null;
24-
}
17+
return null;
2518
}
2619

2720
export default NullField;
Lines changed: 19 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { Component } from "react";
1+
import React, { useState } from "react";
22
import { asNumber, FieldProps } from "@rjsf/utils";
33

44
// Matches a string that ends in a . character, optionally followed by a sequence of
@@ -13,10 +13,6 @@ const trailingCharMatcherWithPrefix = /\.([0-9]*0)*$/;
1313
// different matchers.
1414
const trailingCharMatcher = /[0.]0*$/;
1515

16-
type NumberFieldState = {
17-
lastValue: any;
18-
};
19-
2016
/**
2117
* The NumberField class has some special handling for dealing with trailing
2218
* decimal points and/or zeroes. This logic is designed to allow trailing values
@@ -34,30 +30,20 @@ type NumberFieldState = {
3430
* value cached in the state. If it matches the cached value, the cached
3531
* value is passed to the input instead of the formData value
3632
*/
37-
class NumberField<T = any, F = any> extends Component<
38-
FieldProps<T, F>,
39-
NumberFieldState
40-
> {
41-
/** Constructs the `NumberField` from the `props`
42-
*
43-
* @param props - The `FieldProps` for this component
44-
*/
45-
constructor(props: FieldProps<T, F>) {
46-
super(props);
33+
function NumberField<T = any, F = any>(props: FieldProps<T, F>) {
34+
const { registry, onChange, formData, value: initialValue } = props;
35+
const [lastValue, setLastValue] = useState(initialValue);
36+
const { StringField } = registry.fields;
4737

48-
this.state = {
49-
lastValue: props.value,
50-
};
51-
}
38+
let value = formData;
5239

5340
/** Handle the change from the `StringField` to properly convert to a number
5441
*
5542
* @param value - The current value for the change occurring
5643
*/
57-
handleChange = (value: any) => {
58-
const { onChange } = this.props;
44+
const handleChange = (value: FieldProps<T, F>["value"]) => {
5945
// Cache the original value in component state
60-
this.setState({ lastValue: value });
46+
setLastValue(value);
6147

6248
// Normalize decimals that don't start with a zero character in advance so
6349
// that the rest of the normalization logic is simpler
@@ -76,32 +62,20 @@ class NumberField<T = any, F = any> extends Component<
7662
onChange(processed as unknown as T);
7763
};
7864

79-
/** Renders the `NumberField` dealing with resolving the `lastValue` and current `value`
80-
*/
81-
render() {
82-
const { StringField } = this.props.registry.fields;
83-
const { formData, ...props } = this.props;
84-
const { lastValue } = this.state;
65+
if (typeof lastValue === "string" && typeof value === "number") {
66+
// Construct a regular expression that checks for a string that consists
67+
// of the formData value suffixed with zero or one '.' characters and zero
68+
// or more '0' characters
69+
const re = new RegExp(`${value}`.replace(".", "\\.") + "\\.?0*$");
8570

86-
let value = formData;
87-
88-
if (typeof lastValue === "string" && typeof value === "number") {
89-
// Construct a regular expression that checks for a string that consists
90-
// of the formData value suffixed with zero or one '.' characters and zero
91-
// or more '0' characters
92-
const re = new RegExp(`${value}`.replace(".", "\\.") + "\\.?0*$");
93-
94-
// If the cached "lastValue" is a match, use that instead of the formData
95-
// value to prevent the input value from changing in the UI
96-
if (lastValue.match(re)) {
97-
value = lastValue as unknown as T; // Need to cast
98-
}
71+
// If the cached "lastValue" is a match, use that instead of the formData
72+
// value to prevent the input value from changing in the UI
73+
if (lastValue.match(re)) {
74+
value = lastValue as unknown as T;
9975
}
100-
101-
return (
102-
<StringField {...props} formData={value} onChange={this.handleChange} />
103-
);
10476
}
77+
78+
return <StringField {...props} formData={value} onChange={handleChange} />;
10579
}
10680

10781
export default NumberField;

packages/fluent-ui/jest.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module.exports = {
22
moduleNameMapper: {
3-
'office-ui-fabric-react/lib/': 'office-ui-fabric-react/lib-commonjs/'
3+
"office-ui-fabric-react/lib/": "office-ui-fabric-react/lib-commonjs/",
4+
"^react$": "<rootDir>/node_modules/react",
5+
"^react-dom$": "<rootDir>/node_modules/react-dom",
46
},
57
testEnvironment: "jsdom",
68
testEnvironmentOptions: {

packages/material-ui/jest.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
moduleNameMapper: {
3+
"^react$": "<rootDir>/node_modules/react",
4+
"^react-dom$": "<rootDir>/node_modules/react-dom",
5+
},
6+
};

packages/mui/jest.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
module.exports = {
2+
moduleNameMapper: {
3+
"^react$": "<rootDir>/node_modules/react",
4+
"^react-dom$": "<rootDir>/node_modules/react-dom",
5+
},
26
snapshotSerializers: ["@emotion/jest/serializer"],
37
testEnvironment: "jsdom",
48
testEnvironmentOptions: {

packages/semantic-ui/jest.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
moduleNameMapper: {
3+
"^react$": "<rootDir>/node_modules/react",
4+
"^react-dom$": "<rootDir>/node_modules/react-dom",
5+
},
6+
};

0 commit comments

Comments
 (0)