简体   繁体   中英

how to create re-usable field component in redux-form?

I have 2-3 fields that is reused is other forms of my application. So i wanted to create those fields as component so that I can resuse is my other forms. but redux-form is complaining that

Error: Field must be inside a component decorated with reduxForm()

Any ideas how can I achieve it? BTW, I am using material-ui

EDIT: providing a better eg consider the material-ui toolbar

http://www.material-ui.com/#/components/toolbar

My toolbar consists of a selectField, textField, Toggle button, which may couple of forms. In my app, I want to keep this toolbar in all the forms where I create objects in my application, so I want to include this toolbar in all the forms. After the below answer I tried something dirty like below.

class BaseBar extends React.Component { // eslint-disable-line react/prefer-stateless-function
    constructor(props) {
        super(props);
        this.state = {
            value: 3,
            isGlueOpen: false,
        };
    }

    handleChange = (event, index, value) => {
        this.setState({value: value});
    }

  render() {
    return (
      <div>
          <Toolbar>
              <ToolbarGroup firstChild={true}>
                  <DropDownMenu value={this.state.value} onChange={this.handleChange}>
                      <MenuItem value={1} primaryText="All Broadcasts" />
                      <MenuItem value={2} primaryText="All Voice" />
                      <MenuItem value={3} primaryText="All Text" />
                      <MenuItem value={4} primaryText="Complete Voice" />
                      <MenuItem value={5} primaryText="Complete Text" />
                      <MenuItem value={6} primaryText="Active Voice" />
                      <MenuItem value={7} primaryText="Active Text" />
                  </DropDownMenu>
              </ToolbarGroup>
              <ToolbarSeparator />
              <ToolbarGroup>
                  <ToggleButton onChange={this.props.glueToggle}/>
              </ToolbarGroup>
          </Toolbar>
      </div>
    );
  }
}


export default BaseBar;

and including the form like below

 <form onSubmit={handleSubmit}>
          <div>
              <Field
                  name="basebar"
                  component={BaseBar}
                  label="project"
              />
          </div>
          <div>
              <Field
                  name="subject"
                  component={renderTextField}
                  label="subject"
              />
          </div>
   </form>

But on submit, I am getting the values for subject field but not the basebar values, any suggestions or approach is greatly appreciated.

The error is that you're trying to use the Field outside the context of a connected Redux Form.

Perhaps you could create your shareable component without the <Field> component itself, and then use that component in as many forms as you need, wrapping it with Field . See example usage in the documentation:

http://redux-form.com/6.8.0/docs/api/Field.md/#usage

import MyCustomInput from './MyCustomInput'

...

<Field name="myField" component={MyCustomInput}/>

Where MyCustomInput is your custom, common component.

Or if you have custom logic to map Field props to your components, then use a function which you can then export and reuse in as many forms as you need.

// this is your custom component now
export const renderMyCustomField = (field) => (
    <div className="input-row">
      <input {...field.input} type="text"/>
      {field.meta.touched && field.meta.error && 
       <span className="error">{field.meta.error}</span>}
    </div>
  )
...
//which you can then import in your forms
import { renderMyCustomField } from '...'

// inside your render() method
<Field name="myField" component={renderMyCustomField}/>

Welcome to reusable redux form field component :) Here my elegant soloution:

import React from 'react';
import { string, object } from 'prop-types';
import { Field } from 'redux-form/immutable';

const Input = ({
  input,
  meta: { touched, error },
  ...rest
}) => (
  <div>
    <input
      {...input}
      {...rest}
    />
    {touched && error && <span>{error}</span>}
  </div>
);

Input.propTypes = {
  input: object.isRequired,
  meta: object.isRequired,
  type: string.isRequired
};

Input.defaultProps = {
  input: null,
  meta: null,
  type: 'text'
};

export default props => <Field {...props} component={Input} />;

How to use?

import Input from './Input';

<form>
...

<Input
  autoComplete="off"
  name="email"
  placeholder="Email"
  type="email"
/>
...
</form>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM