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
Related
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();
I am new in React. As I read many documents, I realized that the state of the application should managed outside each components. And I choose Redux for my project.And I tried to pass username and password from my SigIn component. But when I click on the login button , the default statement inside the switch is always executed.The code are given below.
SignIn.jsis as below
import React from 'react';
import Header from './Head.js';
import { logIn } from '../actions/index.js';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
class SignIn extends React.Component{
constructor(){
super();
this.logInClick = this.logInClick.bind(this);
}
logInClick() {
let { dispatch } = this.props;
const data = {username:'sojimon#gmail.com', password:'12345'}
// this.props.logIn(data);
this.props.dispatch(logIn(data));
}
render(){
return(
<div>
<Header/>
<br/>
<div className="col-md-4 col-md-offset-4">
<div className="well">
<h4 className="signin_header">Sign In</h4>
<div>
<div>
<label>Email:</label>
<input type="text" className="form-control" />
</div>
<div>
<label>Password:</label>
<input type="text" className="form-control"/>
</div>
<br/>
<button className="btn btn-primary" onClick={ this.logInClick }>Login</button>
</div>
</div>
</div>
</div>
)
}
}
const matchDispatchToProps = (dispatch) => ({
// logIn: (data) => dispatch(logIn(data)),
})
SignIn.propTypes = {
logIn: React.PropTypes.func
}
export default connect (matchDispatchToProps)(SignIn);
And my action/index.js as follows,
import * as types from './types.js';
export const logIn = (state, data) => {
return {
type: types.LOG_IN,
state
}
}
And reducers/logIn.js is,
import React from 'react';
import { LOG_IN } from '../actions/types.js'
const logIn = (state = [], action) => {
switch (action.type) {
case 'LOG_IN':
console.log('switch Case ==> LOG_IN');
return [
...state,
{
username: 'asdf',
password: '123',
}
]
// return action.logIn
default:
console.log('switch Case ==> Default');
return state
}
}
export default logIn
And created store in index.js file as,
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app/App';
import './app/index.css';
import Routes from './app/route';
import { createStore } from 'redux' // import store
import { Provider } from 'react-redux' // import provider
import myApp from './app/reducers/index.js'
let store = createStore(myApp);
ReactDOM.render(
<Provider store={store}>
<Routes />
</Provider>,
document.getElementById('root')
);
export default store;
Struggling to dispatch an action from my React component. This is my first Redux app. Everything seems to be working fine, but if it was I would not be posting this question. I am using Redux devTool to debug my app. If I use the dispatcher from the devTools my reducer is triggered with no problem. However I am unable to dispatch the same action from my React components. I added a breakpoint in my action to see if it was being triggered. I definately is and it is also returning a valid action (type & payload). Here is my code:
store.js
import {createStore, applyMiddleware, compose} from 'redux'
import {createLogger} from 'redux-logger'
import thunk from 'redux-thunk'
import promise from 'redux-promise-middleware'
import reducers from './reducers/index'
const logger = createLogger()
const store = createStore(
reducers,
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__(),
compose(
applyMiddleware(thunk, promise, logger)
)
)
export default store
reducers (index.js)
import {combineReducers} from 'redux'
import userReducer from './userReducer'
const allReducers = combineReducers({
user: userReducer
})
export default allReducers
client.js
import React from 'react'
import ReactDOM from 'react-dom'
import {Provider} from 'react-redux'
import store from './store'
import Router from './modules/router'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import getMuiTheme from 'material-ui/styles/getMuiTheme'
import CustomTheme from './modules/theme'
import injectTapEventPlugin from 'react-tap-event-plugin'
require('../scss/style.scss')
// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
injectTapEventPlugin();
ReactDOM.render(
<Provider store={store}>
<MuiThemeProvider muiTheme={CustomTheme}>
<Router/>
</MuiThemeProvider>
</Provider>,
document.getElementById('app')
);
userReducer.js
export default function (state = {loggedIn: false}, action) {
console.log("THIS IS THE REDUCER: STATE: ", state, " - ACTION: ", action)
switch (action.type) {
case 'LOGIN':
return {...state, loggedIn: action.payload}
}
return state;
}
userActions.js
export const login = () => {
console.log("TEST")
return {
type: 'LOGIN',
payload: true
}
}
login.js
import React from 'react'
import ReactDOM from 'react-dom'
import LoginForm from '../containers/loginform'
class Login extends React.Component {
render() {
return (
<LoginForm/>
)
}
}
export default Login
loginform.js
import React, {PropTypes} from 'react'
import ReactDOM from 'react-dom'
import {Redirect} from 'react-router-dom'
import {connect} from 'react-redux'
import {login} from '../actions/userActions'
import RaisedButton from 'material-ui/RaisedButton'
import TextField from 'material-ui/TextField'
class LoginForm extends React.Component {
constructor(props) {
super(props)
}
loginReq(e){
e.preventDefault()
this.props.login()
}
render() {
return (
<div>
<form className='login-form-container' onSubmit= {this.loginReq.bind(this)}>
<div className='login-form-row'>
<TextField
ref='email'
hintText='Email'
floatingLabelText='Email'
className='login-form-field'/>
</div>
<div className='login-form-row'>
<TextField
ref='password'
hintText='Password'
floatingLabelText='Password'
type='password'
className='login-form-field'/>
</div>
<div className='login-form-row'>
<RaisedButton
type= 'submit'
label='Login'
className='login-form-button'/>
</div>
</form>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
loggedIn: state.user.loggedIn
}
}
const mapDispatchToProps = (dispatch) => {
return {
login: () => dispatch(login())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm)
Please could you give me some guidance to how else i can debug to find out why this dispatch is not working. I have tried adding the action object straight into that dispatch function. still no luck. I get no errors in the console nothing. My console.logs are only printed when the view renders and when i click on the login submit button.
Console Screenshot
Finally found my issue. My middleware implementation was causing the issue. I was passing in promise incorrectly. Should be:
import {createStore, applyMiddleware} from 'redux'
import {composeWithDevTools} from 'redux-devtools-extension'
import {createLogger} from 'redux-logger'
import thunk from 'redux-thunk'
import promise from 'redux-promise-middleware'
import reducers from './reducers/index'
const logger = createLogger()
const middleware = applyMiddleware(promise(), logger, thunk)
const store = createStore(reducers, composeWithDevTools(middleware))
export default store
Also found that redux-devtools-extension was cleaner for Redux devTools.
My hunch would be how you are trying to invoke the function to dispatch the action. Firstly, bind the function to this in the component constructor (See the React docs on event handlers here for more info). Secondly, just pass the function to onSubmit.
class LoginForm extends React.Component {
constructor(props) {
super(props)
this.loginReq = this.loginReq.bind(this);
}
loginReq(e) {
e.preventDefault()
this.props.login()
}
render() {
return (
<div>
<form className='login-form-container' onSubmit={this.loginReq}>
<div className='login-form-row'>
<TextField
ref='email'
hintText='Email'
floatingLabelText='Email'
className='login-form-field'/>
</div>
<div className='login-form-row'>
<TextField
ref='password'
hintText='Password'
floatingLabelText='Password'
type='password'
className='login-form-field'/>
</div>
<div className='login-form-row'>
<RaisedButton
type= 'submit'
label='Login'
className='login-form-button'/>
</div>
</form>
</div>
)
}
}
An alternative way to bind the function to this is to remove the bind statement in the constructor and use an arrow function for the form prop, like this:
onSubmit={e => this.loginReq(e)}
modify action:
export const login = () => {
return function (dispatch) {
console.log('here');
dispatch({
type: 'LOGIN',
payload: true
});
}
}
I guess you'd like => syntax in that case.
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
}
}
Going through udemy tutorial and got stuck and for some reason can't figure out what happaned. I went through all my code and it looks right as far as I can tell compared to the tutorial. Code:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from 'redux-promise';
import App from './components/app';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<App />
</Provider>
, document.querySelector('.container'));
searchbar.js:
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {fetchWeather} from '../actions/index';
export default class SearchBar extends Component{
constructor(props){
super(props);
this.state = {term: ''}
this.onInputChange = this.onInputChange.bind(this)
}
onInputChange(e){
console.log(e.target.value)
this.setState({
term: e.target.value
})
}
onFormSubmit(e){
e.preventDefault()
}
render(){
return (
<form onSubmit ={this.onFormSubmit} className = "input-group">
< input
placeholder =" Get a forecast"
className = "form-control"
value = {this.state.term}
onChange = {this.onInputChange}
/>
<span className = "input-group-btn">
<button type="submit" className = "btn btn-secondary">Submit </button>
</span>
</form>
);
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({fetchWeather}, dispatch);
}
export default connect (null, mapDispatchToProps)(SearchBar);
reducers/index.js
import axios from 'axios';
const API_KEY = 'c4c2ff174cb65bad330f7367cc2a36fa'
const ROOT_URL = `http://api.openweathermap.org/data/2.5/forecast?q=appid=${API_KEY}`;
export const FETCH_WEATHER = 'FETCH_WEATHER';
export function fetchWeather(city){
let url = `${ROOT_URL}&q=${city},us`;
let request = axios.get(url);
return {
type: FETCH_WEATHER,
payload: request
};
}
app.js
import React, { Component } from 'react';
import SearchBar from '../containers/search_bar';
export default class App extends Component {
render() {
return (
<div>
<SearchBar />
</div>
);
}
}
To answer,
Your code got a little mixed up, the block that you have in reducers/index.js is your action and should be located in actions/index.js instead. As mentioned you are importing it from there in your searchbar component:
import {fetchWeather} from '../actions/index';
The reducer here should be making use of the FETCH_WEATHER type that you are setting up in your action in order to update the state of the redux store, so something along the lines of:
switch(action.type) {
case FETCH_WEATHER:
return [action.payload.data].concat(state);
}
return state;
Then either export that directly or make use of combineReducers from redux to return a single reducer function if you have more than one.
Link to the always awesome: DOCS