The main reason you could say we moved to Redux was validation. We didn’t want to add a whole lot of code to our page components to validate every child component. In some components, we had up to ten fields, and all of them had to be validated. Can you imagine the size of the component that validated all of these? Hundreds of lines long. For some of you, that’ll be okay. I mean, why can’t a component be long? For us, it’s about maintainability and having a large component is hard to navigate and see what it looks like.
Along came React-Redux-Forms
From the previous posts, you might’ve seen that we use Bootstrap within our React. And that’s true. We needed a way to be able to validate the Bootstrap components while not adding too much code. React-Redux-Form makes that pretty easy. It’s just a wrapper around your component (in this case the Bootstrap components) that encapsulate all the things you need when validating. It’ll handle all the stuff like dirty, touched etc. for you.
I’ve created a really basic example for you below. You must always surround your forms with a form tag. This is important as that’s where you’ll get submit etc. from. Firstly, I’ve created a component that is three buttons. Two create valid values, and we want the third to trigger an invalid value.
import * as React from 'react'; import { Button } from 'react-bootstrap'; interface MyProps { onChange: (name: string) => void; value: string; } export const MyComponent: React.StatelessComponent<MyProps> = (props) => { const onButtonClickJohn = () => { props.onChange('John'); }; const onButtonClickJacob = () => { props.onChange('Jacob'); }; const onButtonClickMichael = () => { props.onChange('Michael'); }; return ( <div> <span>{props.value}</span> <Button onClick={onButtonClickJohn}>John</Button> <Button onClick={onButtonClickJacob}>Jacob</Button> <Button onClick={onButtonClickMichael}>Michael</Button> </div> ); };
Here’s the component in a form.
import * as React from 'react'; import MyComponent from './MyComponent'; import { Control, Form } from 'react-redux-form'; export interface MyComponentFormProps { viewModel: { myComponent: string; }; } export default class MyComponentForm extends React.Component<MyComponentFormProps, {}>{ constructor(props: MyComponentFormProps) { super(props); } handleSubmit() { console.log('submitted'); } render() { const mapProps = { value: (props: MapPropsProps) => props.viewValue, }; const validators = () => ({ isNotMichael: (val: any): boolean => { if (val === 'Michael') { return false; } return true; }, }); return ( <Form className="myComponentForm" model="myComponentForm" onSubmit={this.handleSubmit}> <Control.text component={MyComponent} model={'myComponentForm.myComponent'} mapProps={mapProps} validators={validators} updateOn="change" /> <Errors model="myComponentForm.myComponent" messages={{ isNotMichael: 'Please don't choose michael.', }} /> </Form> ); } }
You need to add a little something to your reducers. There’s now a form part – if you need to access valid/invalid etc.
import React from 'react'; import { createStore } from 'redux'; import { combineForms } from 'react-redux-form'; const initialMyComponentForm = { myComponent: '' }; const store = createStore(combineForms({ myComponentForm: initialMyComponentForm, }));
Yours won’t be so easy
The above example is a relatively benign example of how you might introduce React-Redux-Forms to your React-Redux code. I also haven’t tested if it compiles, so let me know if it’s working. Unfortunately, life is not so easy. What you’ll find is that your forms will become more complicated. You’ll have components that need to be reused. You’ll have validators that need to be reused. Everything should be tested and be testable. And, to top it all off, you’ll probably want clean code that doesn’t pollute your components with validation logic or all this form stuff.
Reposted on Medium.
Leave a Reply