警告:propType 失败:在 `SignUp` 中未指定必需的 prop `emailExists`

Warning: Failed propType: Required prop `emailExists` was not specified in `SignUp`

收到这些警告:

Warning: Failed propType: Required prop emailExists was not specified in SignUp

Warning: Failed propType: Required prop onEmailChange was not specified in SignUp

emailExists proponEmailChange prop 未在 components/SignUp.js[=43= 中指定].我猜 mapStateToPropsmapDispatchToProps[=53= 中传递到 connect() .js 没有将 props 注入 components/SignUp.js 由于一些错误配置。

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

问题是,我在 index.js。因此 index.js 中的行 import SignUp from './components/SignUp' 变为 import SignUp from './containers/SignUp'。因为,containers 围绕着 components 并将 Redux states 映射到 React props 并将 Redux dispatches 映射到 React prop callbacks 以及所有 props在需要时注入 componentscontainers 订阅 Redux store 并将新的 props 注入 components 当新的订阅信号到达并且 组件 使用新的 props 更新它们自己。 components 调用 callback props 来更改数据并反过来使 containers 调度 动作。有关详细信息,我们有文档 here.