2.2.4 • Published 5 years ago
@troglotit/react-redux-form-generator v2.2.4
react-redux-form-generator
Forms generator for react/redux apps based on redux-form and JSON-schemas.
Installation
npm install redux-form
npm install react-redux-form-generator
Usage
import _ from "lodash";
import { PureComponent } from "react";
import ReactReduxFormGeneratorWrapper from "./ReactReduxFormGeneratorWrapper";
// We will look closer to the schemas and values below in documentation
import formSchema from "../data/schema.json";
import initialValues from "../data/values.json";
export default class Demo extends PureComponent {
state = {
savedValues: initialValues,
invalidateFields: {}
};
componentWillMount() {
const savedValues = JSON.parse(localStorage.getItem("demo"));
if (savedValues) this.setState({ savedValues });
}
handleChange = values => {
console.log("Demo -> handleChange", { values });
};
handleSubmit = values => {
localStorage.setItem("demo", JSON.stringify(values));
};
handleValidate = invalidateFields => {
this.setState({ invalidateFields });
};
render() {
const { savedValues, invalidateFields } = this.state;
return (
<>
<h2>ReactReduxFormGenerator</h2>
<hr />
<ReactReduxFormGeneratorWrapper
id="demo"
form="demo"
schema={formSchema}
context={this}
initialValues={savedValues}
onChange={this.handleChange}
onSubmit={this.handleSubmit}
onValidate={this.handleValidate}
/>
<button form="demo" type="submit">
Submit after valid
</button>
</>
);
}
}
Wrapper
The form generator uses the user-provided React Components for form fields (Input, Select, RadioButton etc.) and validation functions (for example required, onlyDigits). So, firstly, you need to create a wrapper that provides the generator with templates and validators and connects it to the redux-storage of the application.
You can simply copy and paste this file and only change templates and validators to yours:
import _ from "lodash";
import { compose } from "redux";
import { Component } from "react";
import { connect } from "react-redux";
import { reduxForm, Field, getFormValues, getFormSyncErrors } from "redux-form";
// Here you need to import your JSX-templates for the Field wrapper,
// the Fields` Block wrapper and the form controls themselves (Input, Radio etc)
// We`ll look closer to them below in this documentation
import TextField from "./TextField";
import RadioField from "./RadioField";
import SelectField from "./SelectField";
import BlockWrapper from "./BlockWrapper";
import FieldWrapper from "./FieldWrapper";
// Here you need to import your validate functions
// We`ll look closer to them below in this documentation
import * as validators from "../utils/validators";
import ReactReduxFormGenerator from "./ReactReduxFormGenerator";
class ReactReduxFormGeneratorWrapper extends Component {
componentWillReceiveProps({ data: nextData, errors: nextErrors }) {
const {
onChange,
data: prevData,
onValidate,
errors: prevErrors
} = this.props;
// ReactReduxFormGenerator not provides any onChange or onValidate events,
// so if you need this – you need to handle data and errors updates yourself
if (!_.isEqual(nextData, prevData)) onChange(nextErrors);
if (!_.isEqual(nextErrors, prevErrors)) onValidate(nextErrors);
}
render() {
const {
id,
form,
schema,
context,
children,
onChange,
onSubmit,
initialValues
} = this.props;
return (
<ConnectedReactReduxFormGenerator
id={id}
form={form}
Field={Field}
schema={schema}
context={context}
// Specify your validate functions here
validators={validators}
initialValues={initialValues}
onChange={onChange}
onSubmit={onSubmit}
// And here you need to provide your templates
templates={{
block: BlockWrapper,
field: FieldWrapper,
text: TextField,
radio: RadioField,
select: SelectField
}}
>
{children}
</ConnectedReactReduxFormGenerator>
);
}
}
const mapStateToFormGeneratorProps = (state, { form: formName }) => ({
form: formName,
data: getFormValues(formName)(state)
});
const ConnectedReactReduxFormGenerator = compose(
connect(mapStateToFormGeneratorProps),
reduxForm({ enableReinitialize: true })
)(ReactReduxFormGenerator);
const mapStateToGeneratorWrapperProps = (state, { form }) => ({
data: getFormValues(form)(state),
errors: getFormSyncErrors(form)(state)
});
export default connect(mapStateToGeneratorWrapperProps)(
ReactReduxFormGeneratorWrapper
);
Props specification
Form`s schema example
[{
"key": "simple-fields",
"fields": [{
"label": "Text Field",
"name": "text_field",
"type": "text",
"validations": ["required"]
}, {
"label": "Radios Field",
"name": "radios_field",
"type": "radios",
"options": [{
"label": "First",
"value": "1"
}, {
"label": "Second",
"value": "2"
}],
"validations": ["required"]
}, {
"label": "Select Field",
"name": "select_field",
"type": "select",
"options": [{
"label": "First",
"value": "1",
"showIf": "data.radios_field !== '2'"
}, {
"label": "Second",
"value": "2",
"showIf": "data.radios_field !== '1'"
}],
"validations": ["required"]
}]
}]
Validate functions example
export const required = value => !value ? 'Is required!' : undefined;
export const numeric = value => value && isNaN(value) ? 'Need to be a number' : undefined;