Got these warnings:
Warning: Failed propType: Required prop
emailExists
was not specified inSignUp
Warning: Failed propType: Required prop
onEmailChange
was not specified inSignUp
emailExists prop and onEmailChange prop are not specified in components/SignUp.js. I guess mapStateToProps and mapDispatchToProps passed into connect() in containers/SignUp.js is not injecting the props into components/SignUp.js due to some misconfiguration.
index.js:
import React from 'react'
import {render} from 'react-dom'
import {Provider} from 'react-redux'
import {createStore, applyMiddleware} from 'redux'
import {Router, Route, IndexRoute, browserHistory} from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
import createLogger from 'redux-logger'
import thunkMiddleware from 'redux-thunk'
import donrollApp from './reducers'
import App from './components/LoginApp'
import Login from './components/Login'
import SignUp from './components/SignUp'
const loggerMiddleware = createLogger()
let store = createStore(donrollApp, applyMiddleware(thunkMiddleware, loggerMiddleware))
const history = syncHistoryWithStore(browserHistory, store)
render(
<Provider store={store}>
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={Login}/>
<Route path="signup" component={SignUp}/>
<Route path="*" component={Login}/>
</Route>
</Router>
</Provider>,
document.getElementById('root')
);
containers/SignUp.js:
import { connect } from 'react-redux'
import SignUp from '../components/SignUp'
import { fetchEmailExists } from '../actions'
const mapStateToProps = (state, ownProps) => {
return {
emailExists: state.SignUp.emailExists
}
}
const mapDispatchToProps = (dispatch) => {
return {
onEmailChange: (email) => {
dispatch(fetchEmailExists(email))
}
}
}
const SignUpContainer = connect(
mapStateToProps,
mapDispatchToProps
)(SignUp)
export default SignUpContainer
reducers/SignUp.js:
import Immutable from 'immutable'
const SignUp = (state={emailExists:false, isCheckingEmail: false}, action) => {
let newState = Immutable.Record(state);
switch (action.type) {
case 'CHECK_EMAIL_EXISTS_REQUEST':
return (new newState({isCheckingEmail:true})).toJS();
case 'CHECK_EMAIL_EXISTS_RESPONSE':
return (new newState({emailExists: action.emailExists})).toJS();
default:
return state
}
}
export default SignUp
reducers/index.js:
import { combineReducers } from 'redux'
import SignUp from './SignUp'
import { routerReducer } from 'react-router-redux'
const donrollApp = combineReducers({
SignUp,
routing: routerReducer
})
export default donrollApp
components/SignUp.js:
import React, { PropTypes } from 'react'
import {Link} from 'react-router'
const SignUp = ({emailExists, onEmailChange}) => {
let signupData = {
firstname:{},
lastname:{},
email:{},
username:{},
password:{},
confirmPassword:{}
}
return (
<div>
<form>
<div className="form-group row">
<h4 className="col-sm-12">Sign Up</h4>
</div>
<div className="form-group row">
<label htmlFor="inputFirstname3" className="col-sm-3 col-form-label">Firstname</label>
<div className="col-sm-9">
<input type="text" className="form-control" id="inputFirstname3" placeholder="Firstname" ref={node=>{signupData.firstname=node;}} />
</div>
</div>
<div className="form-group row">
<label htmlFor="inputLastname3" className="col-sm-3 col-form-label">Lastname</label>
<div className="col-sm-9">
<input type="text" className="form-control" id="inputLastname3" placeholder="Lastname" ref={node=>{signupData.lastname=node;}}/>
</div>
</div>
<div className={emailExists?'form-group row has-danger':'form-group row'}>
<label htmlFor="inputEmail3" className="col-sm-3 col-form-label">Email</label>
<div className="col-sm-9">
<input type="email" onBlur={e=>onEmailChange(signupData.email.value)} className="form-control" id="inputEmail3" placeholder="Email" ref={node=>{signupData.email=node;}}/>
{emailExists?<div className="form-control-feedback">Shit, that email's taken. Try another?</div>:null}
</div>
</div>
<div className="form-group row">
<label htmlFor="inputUsername3" className="col-sm-3 col-form-label">Username</label>
<div className="col-sm-9">
<input type="text" className="form-control" id="inputUsername3" placeholder="Username" ref={node=>{signupData.username=node;}}/>
</div>
</div>
<div className="form-group row">
<label htmlFor="inputPassword3" className="col-sm-3 col-form-label">Password</label>
<div className="col-sm-9">
<input type="password" className="form-control" id="inputPassword3" placeholder="Password" ref={node=>{signupData.password=node;}}/>
</div>
</div>
<div className="form-group row">
<label htmlFor="inputConfirmPassword3" className="col-sm-3 col-form-label">Confirm Password</label>
<div className="col-sm-9">
<input type="password" className="form-control" id="inputConfirmPassword3"
placeholder="Confirm Password" ref={node=>{signupData.confirmPassword=node;}}/>
</div>
</div>
<div className="form-group row">
<div className="offset-sm-3 col-sm-9">
<button type="submit" className="btn btn-primary">Sign Up</button>
{" "}
<Link to="/">Login</Link>
</div>
</div>
</form>
</div>
)
}
SignUp.propTypes = {
emailExists: PropTypes.bool.isRequired,
onEmailChange: PropTypes.func.isRequired
}
export default SignUp
const SignUpContainer = connect( mapStateToProps, {fetchEmailExists: onEmailChange} )(SignUp)
. And regarding the other propemailExists
, is themapStateToProps
throwing any error? – DeadfishonEmailChange is not a function
error is thrown. Here, the onBlur event is handled by calling the onEmailChange function, which is not specified. – Kuppuswamy