While wiring up a tiny Edit Profile form with Redux Form using react JS I wrote a component that exported two versions of itself an undecorated class (export class EditProfile
) and the wrapped version returned by reduxForm({ form: 'editForm' })(EditProfile)
and then, in another file, I accidentally imported the named class instead of the default export.
Because <Field>
relies on the context that the reduxForm()
higher-order component injects, rendering the plain class made the library complain: “Field must be inside a component decorated with reduxForm().”
The fix is simply to mount the wrapped component import EditProfile from './EditProfile';
or export only the decorated version so the form fields receive their expected context and the error disappears.
My Code
I wanted to knock together a tiny Edit Profile form with Redux Form, so I wrote this:
React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
export class EditProfile extends Component {
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" component="input" type="text" />
</form>
);
}
}
export default reduxForm({ form: 'editForm' })(EditProfile);
When I hit Save and refreshed, the console shouted:
Error: Field must be inside a component decorated with reduxForm()
The Error Show
<Field>
needs the context that the reduxForm()
higher-order component (HOC) provides.
If the component you mount is not the one wrapped by reduxForm()
, that context never appears and the field throws the error.
My file actually exports two components:
Export line | Name other files can import | Wrapped by reduxForm() ? |
---|---|---|
export class EditProfile … | EditProfile (named import) | ❌ |
export default reduxForm(…)(EditProfile) | default import | ✅ |
So if another file does this:
// pulls in the *plain* class, not the wrapped one
import { EditProfile } from './EditProfile';
the <Field>
inside runs without its wrapper, and React throws the fit you just saw.
Quick Fixes That Silence The Error
- Import the default export instead of the named one
EditProfile from './EditProfile'; // this is the wrapped version
- Only export the wrapped component
EditProfile = props => { /* … */ };
export default reduxForm({ form: 'editForm' })(EditProfile);
- Re-export with a clear name
const DecoratedEditProfile = reduxForm({ form: 'editForm' })(EditProfile); export { DecoratedEditProfile };
Do any one of those and the message disappears.
Fix Code
Below is the version I now show teammates. I added required-field checks, email checks, a reset button, and a fake submit alert so you can see the payload.
Import React from 'react';
import { Field, reduxForm } from 'redux-form';
/* ---------- validators ---------- */
const required = v => (v ? undefined : 'Required');
const email = v =>
v && !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(v)
? 'Invalid e-mail'
: undefined;
/* ---------- reusable input ---------- */
const renderInput = ({
input,
label,
type,
meta: { touched, error }
}) => (
<div style={{ marginBottom: 12 }}>
<label>{label}</label>
<input {...input} type={type} />
{touched && error && (
<span style={{ color: 'crimson', marginLeft: 6 }}>{error}</span>
)}
</div>
);
const EditProfile = props => {
const { handleSubmit, reset, pristine, submitting } = props;
/* fake save */
const onSubmit = data => {
console.log('✓ Form data', data);
alert('Saved! (open DevTools → Console to see payload)');
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Field
name="firstName"
component={renderInput}
type="text"
label="First name"
validate={[required]}
/>
<Field
name="email"
component={renderInput}
type="email"
label="Email"
validate={[required, email]}
/>
<div style={{ marginBottom: 12 }}>
<label>
<Field name="newsletter" component="input" type="checkbox" />
{' '}Subscribe to newsletter
</label>
</div>
<button type="submit" disabled={submitting}>
{submitting ? 'Saving…' : 'Save'}
</button>{' '}
<button
type="button"
disabled={pristine || submitting}
onClick={reset}
>
Reset
</button>
</form>
);
};
export default reduxForm({
form: 'editProfile',
initialValues: { newsletter: true }
})(EditProfile);
Explain
Try this | Why it’s useful |
---|---|
enableReinitialize: true and feed fresh initialValues from a parent | Reloads user data every time the profile page opens. |
Replace the e-mail <input> with a <select> of domains and assemble the full address in onSubmit | Shows how to build a payload from multiple form parts. |
Use warn instead of validate on the newsletter checkbox | Demonstrates gentle “are you sure?” messages without blocking submit. |
Listen for submitSucceeded and redirect to a Thank You route | Mirrors the flow of most production forms. |
Swap inline styles for CSS modules, Tailwind, or another system | Keeps logic and styles tidy and separate. |
Final Thought
When I see “Field must be inside a component decorated with reduxForm()
” I now know it means one thing: I’m rendering a <Field>
before the wrapper shows up, usually because I imported the wrong component. Grabbing the decorated version fixes it instantly. Once that’s sorted, you’re free to pile on validation, resets, initial data, and all the polished behaviour a real project needs.