I was trying to do some form validations in react js , while Using redux form am facing one error Field must be inside a component decorated with reduxForm() .
i just searched for this error on web but didn't get any solution for that .
Reference Link : http://redux-form.com/6.8.0/examples/simple/ .
Here is my code ,
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
export class EditProfile extends Component {
render() {
console.log("hello welcome");
const { handleSubmit, pristine, reset, submitting } = this.props;
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" component="input" type="text"/>
</div>
</form>
);
}
}
export default reduxForm({
form: 'editForm'
})(EditProfile)
What i did wrong in my code , can someone clarify me .
You have both default export (which is decorated with reduxForm) and named export (not decorated).
I'm assuming you're importing your form like this:
import { EditProfile } from 'EditForm'; // Using named export
Instead you need to import the default one:
import EditProfile from 'EditForm'; // Default export
Technically there's no error, and babel doesn't complain as you're exporting both from the same file. And in some cases it makes sense to export both (e.g. export undecorated one for testing purposes). But in my work I prefer to have only one default export to prevent shooting myself in the foot.
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
export class EditProfile extends Component {
render() {
console.log("hello welcome");
const { handleSubmit, pristine, reset, submitting } = this.props;
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" component="input" type="text"/>
</div>
</form>
);
}
}
EditProfile = reduxForm({
form: 'editForm'
})(EditProfile)
export default EditProfile;
I also faced the same issue. The solution is to edit /index.js
and add the following lines of code:
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { reducer as formReducer } from 'redux-form';
const rootReducer = combineReducers({
form: formReducer,
});
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
Related
Getting this error but I can't really find an issue with my code. The error points towards the ReactDOM.render line of code. but I can't find the issue.
Re-factored my code to no avail. I went through other variable declarations and everything in my code but I can't seem to find anything that'd make the error go away!
import React from 'react';
import { Field,reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { createStream } from '../../actions/index';
class StreamCreate extends React.Component {
renderError=({error,touched})=>{
if(touched && error){
return (
<div className="ui error message">
<div className="header">{error}</div>
</div>
);
}
}
renderInput=({ input,label,meta })=>{
const className=`field ${meta.error && meta.touched ? 'error':''}`;
return (<div className={className}>
<label>{label}</label>
<input {...input} autoComplete="off"/>
{this.renderError(meta)}
</div>
);
}
onSubmit=(formValues)=>{
this.props.createStream(formValues);
};
//redux-form changes it all!
render(){
return (
<form onSubmit={this.props.handleSubmit(this.onSubmit)} className="ui form error">
<Field name="title" component={this.renderInput} label="Enter Title"/>
<Field name="description" component={this.renderInput} label="Enter Description"/>
<button className="ui button primary">Submit</button>
</form>
);
}
}
const validate=(formValues)=>{
const errors={};
if(!formValues.title){
errors.title ='You must enter a title'
}
if(!formValues.description){
errors.description='you must enter a description'
}
return errors;
};
const formWrapped = reduxForm({
form: 'streamCreate',
validate: validate
})(StreamCreate);
export default connect(null,{ createStream })(formWrapped);
//My app.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from 'redux';
import reduxThunk from 'redux-thunk';
import App from './components/App';
import reducers from './reducers/index';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducers,composeEnhancers(applyMiddleware(reduxThunk)));
ReactDOM.render(<Provider store={store}><App/></Provider>,document.querySelector('#root'));
//reducers index.js
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
import authReducer from './authReducer';
export default combineReducers({
auth: authReducer,
form: formReducer
});
//authreducer.js
import { SIGN_IN,SIGN_OUT} from '../actions/types';
const INITIAL_STATE={
isSignedIn: null,
userId: null
};
export default(state=INITIAL_STATE,action) =>{
switch(action.type){
case SIGN_IN:
return {...state,isSignedIn: true, userId: action.payload };
case SIGN_OUT:
return {...state,isSignedIn: false, userId: null };
default:
return state;
}
};
No error and to be able to view the page
Update Your Redux-form to Version 8.1.Because Your Code is according to Version 8.1. Redux-form is reWritten Totally in Version 6.1 .Here is the Link to Version 8.1 Guide.
v5 → v6 Migration Guide
npm i -S redux-form#8.1
or if you use yarn
yarn add redux-form#8.1
Why?
By mistake latest tag in redux-form points to 5.4.0.
$ yarn -s info redux-form dist-tags
{ latest:
'5.4.0',
rc:
'8.0.0-0',
old:
'5.3.6',
alpha:
'7.0.0-alpha.9' }
The issue is tracked here: https://github.com/erikras/redux-form/issues/4405
I'm refactoring some code on my first react app, which is a simple login form that redirects and renders a list of items on successful login. I have a form container, connected to the redux store, that should render a login form - decorated with reduxForm. I don't understand why the form is not rendering.
index.jsx
ReactDOM.render(
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>,
document.getElementById('app')
);
App.jsx
import {LoginFormContainer} from './components/Login/LoginFormContainer'
class App extends Component {
render() {
return (
<Switch>
<Route exact path='/' component={LoginFormContainer}/>
</Switch>
)
}
}
export default App
LoginFormContainer.jsx
import LoginFormComponent from './LoginFormComponent';
import {reduxForm} from 'redux-form/immutable';
import {withRouter} from 'react-router-dom';
let LoginFormContainer = reduxForm({
form: 'login',
})(LoginFormComponent)
const mapStateToProps = null
const mapDispatchToProps = dispatch => {
return {
onSubmit: loginFormValues => {
dispatch(loginUser(loginFormValues))
}
}
}
const mergeProps = (stateProps, dispatchProps, ownProps) =>
Object.assign({}, stateProps, dispatchProps, ownProps)
LoginFormContainer = withRouter(connect(mapStateToProps, mapDispatchToProps, mergeProps)(LoginFormContainer))
export default LoginFormContainer
LoginFormComponent.jsx
class LoginForm extends Component {
render() {
return (
<Row>
<Col xs={12} md={12}>
<form>
<FormGroup>
<Field
name="username"
type="email"
component={renderField}
label="Username"
validate={[required]}
/>
</FormGroup>
<FormGroup>
<Field
name="password"
type="password"
component={renderField}
label="Password"
validate={[required]} />
</FormGroup>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</Col>
</Row>
)
}
}
export default LoginForm
Simply removing the curly braces from the import of LoginFormContainer in App.jsx fixed the issue. import LoginFormContainer from './components/Login/LoginFormContainer'
Just a few minor exports/imports missing.
LoginFormContainer.jsx
import LoginFormComponent from './login_form_component';
import {reduxForm} from 'redux-form/immutable';
import {withRouter} from 'react-router-dom';
import { connect } from 'react-redux'; // missing import
// need to export these variables to be used below
export const LoginFormContainer = reduxForm({
form: 'login',
})(LoginFormComponent)
export const mapStateToProps = null
export const mapDispatchToProps = dispatch => {
return {
onSubmit: loginFormValues => {
dispatch(loginUser(loginFormValues))
}
}
}
// this is not needed
// export const mergeProps = (stateProps, dispatchProps, ownProps) =>
// Object.assign({}, stateProps, dispatchProps, ownProps)
// withRouter is not needed unless you need any of the
// functionality here https://reacttraining.com/react-router/web/api/withRouter
export default connect(mapStateToProps, mapDispatchToProps)(LoginFormContainer)
LoginFormComponent.jsx
Not sure if you just did not include the imports for this file. Make sure to have this in there
import React, { Component } from 'react';
i create simple signin form for my website.
But i have a little problem.
When i type login and password and try send it to server i got error
Uncaught TypeError: this.props.signinUser is not a function
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import * as actions from '../../actions';
class Signin extends Component{
constructor(props){
super(props);
this.state= {};
this.onSubmit = this.onSubmit.bind(this);
}
renderField(field){
return(
<div className="form-group">
<label>{field.label}</label>
<input
className="form-control"
type="text"
{...field.input}
/>
</div>
);
}
onSubmit(e){
e.preventDefault();
let {login,password} = this.state;
//this.props.login(login,password);
console.log({login,password});
this.props.signinUser({login,password});
this.setState({
login: '',
password: ''
})
}
render(){
let {login,password} = this.state;
return(
<form onSubmit={this.onSubmit}>
<Field
label="Login:"
name="login"
component={this.renderField}
onChange={e => this.setState({login: e.target.value})}
/>
<Field
label="Password:"
name="password"
component={this.renderField}
onChange={e => this.setState({password: e.target.value})}
/>
<button action="submit" className="btn btn-primary"> Sign In </button>
</form>
);
}
}
function mapStateToProps(state) {
return { form: state.form };
}
export default reduxForm({
form: 'signin'
}, mapStateToProps, actions)(Signin);
And Actions.
import axios from 'axios';
export function signinUser({login,password}){
return function(dispatch){
axios.post('http://localhost:8080/auth', { login, password});
};
}
and finally reducer.
import { combineReducers } from 'redux';
import { reducer as fromReducer } from 'redux-form';
const rootReducer = combineReducers({
form: fromReducer
});
export default rootReducer;
I use react 16, react redux v5 and react-router v3, react form v7!
I think its problem with connect function from ReactForm!
The problem lies here
export default reduxForm({
form: 'signin'
}, mapStateToProps, actions)(Signin);
This should be
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
....
//remainder of the code
....
mapDispatchToProps =(dispatch)=>{
return {
actions : bindActionCreators(actions , dispatch)
};
}
Signin= connect(
mapStateToProps,
mapDispatchToProps
)(Signin);
export default reduxForm({
form: 'signin'
})(Signin);
You would need to change the call this.props.signinUser to this.props.actions.signinUser
More info at : https://redux-form.com/7.0.4/docs/faq/howtoconnect.md/
I'm utilizing Redux form and the Redux Material UI package. Normally when I run code like this, it works, but for some reason, it's not able to get the value of the TextField. Does anyone know what's going on here?
My console.log statement just comes back with {special_instructions: undefined}
import React from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form/immutable';
/**
* Components
*/
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';
export class EditRequestForm extends React.Component { // eslint-disable-line react/prefer-stateless-function
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
cancel() {
this.props.handleCancelEdit();
}
onSubmit(formProps) {
const request = {
special_instructions: formProps.get('special_instructions'),
};
console.log('request', request);
}
render() {
// console.log(this.props.request);
const { handleSubmit, pristine, reset, submitting, errors } = this.props
let request = this.props.request;
return (
<form className="page-form__wrapper page-body__wrapper read-request-page">
<TextField
name="area_instructions"
multiLine={true}
fullWidth={true}
id="area_instructions"
defaultValue={request.area_instructions}
/>
<div className="page-form__block draft-field bg-grey">
<RaisedButton
primary={true}
onTouchTap={handleSubmit(this.onSubmit)}
label="Update"
/>
<RaisedButton
secondary={true}
onTouchTap={handleSubmit(::this.cancel)}
label="Cancel"
/>
</div>
</form>
);
}
}
function mapDispatchToProps(dispatch) {
return {
dispatch,
};
}
export default reduxForm({
form: 'editRequest',
})(connect(mapDispatchToProps)(EditRequestForm));
I'm not able to type values in input fields using redux-form. I have the following reducer
import {combineReducers} from 'redux';
import session from './sessionReducer';
import profile from './profileReducer';
import map from './mapReducer';
import { reducer as formReducer } from 'redux-form'
const rootReducer = combineReducers({
// short hand property names
session,
profile,
map,
form: formReducer
})
export default rootReducer;
and here is the store
import { createStore, combineReducers, applyMiddleware } from 'redux'
import createLogger from 'redux-logger'
import thunk from 'redux-thunk'
import { routerReducer, routerMiddleware, push } from 'react-router-redux'
import reducers from '../reducers'
import { browserHistory } from 'react-router';
const middleware = [ thunk ];
if (process.env.NODE_ENV !== 'production') {
middleware.push(createLogger());
}
middleware.push(routerMiddleware(browserHistory));
// Add the reducer to your store on the `routing` key
const store = createStore(
combineReducers({
reducers,
routing: routerReducer
}),
applyMiddleware(...middleware),
)
export default store;
component
import React, {PropTypes, Component} from 'react';
import Upload from './Upload';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import * as profileActions from '../../../actions/profileActions';
import EventsCalendar from '../../common/EventsCalendar';
import { Field, reduxForm } from 'redux-form'
import ProfileForm from './ProfileForm';
import {
Form,
FormGroup,
FormControl,
ControlLabel,
Tabs,
Tab,
InputGroup,
Label,
HelpBlock,
Grid,
Row,
Button,
Col
} from 'react-bootstrap';
class Profile extends Component {
static propTypes = {
profile: PropTypes.object.isRequired,
};
constructor(props) {
super(props);
this.state = {
profile: {
username: '',
password: '',
email: ''
}
}
//this.onUpdate = this.onUpdate.bind(this)
}
handleSubmit = (values) => {
// Do something with the form values
console.log(values);
}
componentDidMount() {
this.props.actions.getProfile()
}
componentWillReceiveProps(nextProps) {
if (nextProps.profile !== this.props.profile) {
}
}
render() {
console.log(this.props.profile);
const {profile} = this.props.profile;
const { handleSubmit } = this.props;
return (
<div className="row">
<Col lg={10}>
<Tabs defaultActiveKey={1} id="uncontrolled-tab-example">
<Tab eventKey={1} title="Vendor Data">
<ProfileForm onSubmit={this.handleSubmit} data = {this.props.profile}/>
</Tab>
<Tab eventKey={3} title="Events Calendar">
<EventsCalendar/>
</Tab>
</Tabs>
</Col>
<Col lg={2}>
<Upload/>
</Col>
</div>
);
}
}
function mapStateToProps(state) {
return {
profile: state.default.profile,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(profileActions, dispatch)
};
}
Profile = reduxForm({
form: 'profileForm' // a unique name for this form
})(Profile);
export default connect(mapStateToProps, mapDispatchToProps)(Profile);
when I'm typing I see in console that the state is changing
the attached form component
import React, {Component} from 'react';
import {Field, reduxForm} from 'redux-form';
import FieldFormControl from '../../common/FieldFormControl';
import {
FormGroup,
FormControl,
ControlLabel,
Button
} from 'react-bootstrap';
class ProfileForm extends Component {
render() {
const {handleSubmit, profile, pristine, reset, submitting} = this.props;
return (
<form onSubmit={handleSubmit}>
<FormGroup controlId="signup-name">
<Field type="text" name="firsname" placeholder="test" value component={FieldFormControl}>Vorname</Field>
</FormGroup>
<FormGroup controlId="signup-username">
<Field type="text" name="lastname" placeholder={profile.username} value={profile.username} component={FieldFormControl}>Name</Field>
</FormGroup>
<FormGroup controlId="signup-email">
<Field type="text" name="email" placeholder={profile.username} value={profile.username} component={FieldFormControl}>Vorname</Field>
</FormGroup>
<Button
bsStyle="primary"
type="submit"
//disabled={pristine || submitting}
block
>Speichern</Button>
</form>
);
}
}
// Decorate the form component
ProfileForm = reduxForm({
form: 'profileForm' // a unique name for this form
})(ProfileForm);
export default ProfileForm;
the bootstrap override to be compatible with redux-form
import React, { Component } from 'react';
import {FormGroup, FormControl, ControlLabel} from 'react-bootstrap';
export default class FieldFormControl extends Component {
render () {
const { placeholder, type, input, meta} = this.props;
return (
<FormGroup controlId={input.name} validationState={meta.error ? 'error' : 'success'}>
<ControlLabel>{this.props.children}</ControlLabel>
<FormControl type={type} placeholder={placeholder} value={input.value} onChange={input.onChange} />
<FormControl.Feedback />
</FormGroup>
);
}
}
Remove the value prop from your Field components, redux-form handles updating the value and passing it to the component that you pass it. I'm assuming the idea here is to provide initial value, but this is not the place to do that.
<Field type="text" name="email" placeholder={profile.username} component={FieldFormControl}>Vorname</Field>
You can also pass all the input props to your FormControl in your FieldFormControl so you get onFocus, onBlur, etc., all provided by redux-form.
<FormControl placeholder={placeholder} {...input} />
If you want to initialize the fields with values, either use initialValues when you connect using reduxForm, or initialize if it needs to happen after the form mounts.
And finally, you're using combineReducers twice in such a way that most of your reducers are nested in a way that you didn't intend. To simplify this, I would import the routerReducer in your reducers/index.js file, and add it to your combineReducers there.
const rootReducer = combineReducers({
// short hand property names
session,
profile,
map,
form: formReducer,
routing: routerReducer,
});
Then, in your store, you'll just have
const store = createStore(
reducers,
applyMiddleware(...middleware),
);
You should then see that you'll have all your keys in your state (session, profile, form, routing, etc.) instead of just default and routing.
I do not think it is the redux-form's issue.
Instead, I think your application listens onChange of your input, and dispatch action to redux. So this is the root cause: you dispatch onChange action, causing the redux state to update, (I think your code has not change it in reducer) and after that, redux flushes the render UI.
To fix it, you:
typically, when you dispatch the onChange action, in your reducer, update yuor redux state explicitly. then new state will flush your UI automatically.
e.g. your reducer should have similar like this:
function myReducer(state = initialState, action) {
switch (action.type) {
case MY_INPUT_VALUE_CHANGE:
return Object.assign({}, state, {
vornname: action.data
})
default:
return state
}
}