Last active
August 23, 2017 04:56
-
-
Save bbenezech/528c7057c62300d41f51b212f0a92ad2 to your computer and use it in GitHub Desktop.
redux-form 6 with typescript. Trigger warnings: no semi, multiline comma dangle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react' | |
import { Field, WrappedFieldProps } from 'redux-form' | |
export interface OwnProps { | |
name: string, | |
type?: string, | |
label?: string, | |
help?: string, | |
} | |
interface P extends OwnProps, WrappedFieldProps {} | |
class BootstrapField extends React.PureComponent<P, {}> { | |
renderInput() { | |
// cherry-pick or unload the garbage trunk, as you like | |
const props = { | |
// you can add onFocus or what else | |
onChange: this.props.input.handleChange, | |
value: this.props.input.value, | |
id: this.props.name, // for labels, yo | |
type: this.props.type, | |
} | |
// you'll need a bit more to handle checkboxes and radios | |
// that's a story for another time | |
return props.type === 'textarea' ? | |
<textarea {...props} /> : | |
props.type === 'select' ? | |
<select {...props}> | |
{props.children} | |
</select> : | |
props.children ? | |
React.cloneElement(props.children as any, props) : | |
<input {...props} /> | |
} | |
render() { | |
return <div className="form-group"> | |
{this.props.label && <label htmlFor={this.props.name} className="control-label"> | |
{this.props.label} | |
</label>} | |
<div className="input-group">{ | |
this.renderInput() | |
}</div> | |
{this.props.help && <small className="text-muted">{this.props.help}</small>} | |
</div> | |
} | |
} | |
// create a RF Field typed with the props we want in our bootstrap Field | |
// and export with RF6's inversion of control® already included | |
// to get a nicer API in our forms | |
const MyCustomField = Field as new () => Field<OwnProps> | |
export default class extends React.PureComponent<OwnProps, {}> { | |
render = () => <MyCustomField component={BootstrapField} {...this.props} /> | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react' | |
import BootstrapField from './BootstrapField' | |
import { reduxForm, getFormValues, FormProps, FieldArray } from 'redux-form' | |
import { connect } from 'react-redux' | |
import { AppState, Settings, DispatchProps } from './types' | |
interface StateProps { | |
formValues: Settings | undefined, | |
} | |
interface OwnProps extends FormProps<Settings, AppState> { | |
handleSave: (settings: Settings) => void, | |
} | |
interface P extends OwnProps, StateProps, DispatchProps {} | |
// notice that this.props.handleSubmit! and props.form! need a bang "!" when using strictNullChecks | |
// reason is complicated, you can have a look here: https://github.com/erikras/redux-form/pull/1318#issuecomment-231590672 | |
class SettingsForm extends React.PureComponent<P, {}> { | |
render() { | |
// this.props.handleSubmit => redux form's handler | |
// this.props.handleSave => our controller's handler | |
return <form onSubmit={this.props.handleSubmit!(this.props.handleSave)}> | |
<legend>Settings</legend> | |
<BootstrapField name="sex" label="Sex" type="select"> | |
<option key="" value="">""</option> | |
<option key="m" value="m">Male</option> | |
<option key="f" value="f">Female</option> | |
<option key="o" value="o">Other, complicated, will not disclose</option> | |
</BootstrapField> | |
<BootstrapField name="firstName" label="First name"/> | |
<BootstrapField name="lastName" label="Last name" help="Ask your family if not sure" /> | |
<BootstrapField name="phone" label="Phone" type="phone" /> | |
<div className="btn-toolbar"> | |
<button type="submit" className="btn btn-primary" disabled={this.props.submitting || this.props.pristine}> | |
Process | |
</button> | |
</div> | |
</form> | |
} | |
} | |
// if you need additional stuff from app's state, you totally can connect your form | |
const mapStateToProps = (state: AppState, props: OwnProps): StateProps => ({ | |
formValues: getFormValues<Settings>(props.form!)(state), | |
}) | |
export default connect<OwnProps, StateProps, DispatchProps>(mapStateToProps)(reduxForm({})(SettingsForm)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react' | |
import { connect } from 'react-redux' | |
import { AppState, Settings, DispatchProps } from './types' | |
import SettingsForm from './SettingsForm' | |
// whatever props you may need from owner | |
interface OwnProps { | |
} | |
// whatever props you may need from state | |
interface StateProps { | |
settings?: Settings | |
} | |
interface P extends OwnProps, StateProps, DispatchProps {} | |
class SettingsFormController extends React.PureComponent<P, {}> { | |
handleSave = (settings: Settings) => { | |
this.props.dispatch(/.../) // trigger things in your state | |
console.log('And now I know who you are', settings) | |
// do not google "And now I know who you are" | |
} | |
render() { | |
return <SettingsForm form="settings" handleSave={this.handleSave} /> | |
} | |
} | |
const mapStateToProps = (state: AppState): StateProps => ({ | |
settings: state.settings, | |
}) | |
export default connect<OwnProps, StateProps, DispatchProps>(mapStateToProps)(SettingsFormController) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { FormStateMap } from 'redux-form' | |
export type Settings = { | |
sex: 'm' | 'f' | 'o', | |
firstName: string, | |
lastName: string, | |
phone: string, | |
} | |
export type AppState { | |
form: FormStateMap, | |
settings?: Settings, | |
} | |
export type DispatchProps { | |
dispatch: Function | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I use these typings for RF6: https://gist.github.com/bbenezech/8ebbced86c0f357d09e4000635eea275