Reactjs 警告:失败的propType:未在“注册”中指定必需的prop“emailExists”`

Reactjs 警告:失败的propType:未在“注册”中指定必需的prop“emailExists”`,reactjs,redux,react-router,react-redux,react-router-redux,Reactjs,Redux,React Router,React Redux,React Router Redux,收到以下警告: 警告:失败的propType:Required propemailExists未在注册中指定 警告:失败的propType:未在注册中指定必需的proponEmailChange 组件/SignUp.js中未指定emailExists道具和onEmailChange道具。我猜,由于某些配置错误,传递到containers/SignUp.js中的connect()中的mapStateToProps和mapDispatchToProps并没有将这些道具注入到components/Si

收到以下警告:

警告:失败的propType:Required prop
emailExists
未在注册中指定

警告:失败的propType:未在注册中指定必需的prop
onEmailChange

组件/SignUp.js中未指定emailExists道具和onEmailChange道具。我猜,由于某些配置错误,传递到containers/SignUp.js中的connect()中的mapStateToProps和mapDispatchToProps并没有将这些道具注入到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')
);
reducers/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
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
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
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
组件/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
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
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
import React,{PropTypes}来自“React”
从“反应路由器”导入{Link}
const SignUp=({emailExists,onEmailChange})=>{
设signUpdatea={
名字:{},
姓氏:{},
电邮:{},
用户名:{},
密码:{},
确认密码:{}
}
返回(
注册
名字
{signUpdatea.firstname=node;}}/>
姓氏
{signupdatea.lastname=node;}}/>
电子邮件
onEmailChange(signUpdatea.email.value)}className=“form control”id=“inputEmail3”placeholder=“email”ref={node=>{signUpdatea.email=node;}}}/>
{emailExists?妈的,那封邮件被占用了。再试一封?:null}
用户名
{signupdatea.username=node;}}/>
密码
{signupdatea.password=node;}}/>
确认密码
{signupdatea.confirmPassword=node;}}/>
注册
{" "}
登录
)
}
SignUp.propTypes={
emailExists:PropTypes.bool.isRequired,
onEmailChange:PropTypes.func.isRequired
}
导出默认注册

问题是,我导入了组件/SignUp.js,而不是index.js中的容器/SignUp.js。因此index.js中的行
import-SignUp from./components/SignUp'
变为
import-SignUp from./containers/SignUp'
。因为,容器围绕组件形成一个包裹,将Redux状态映射为React props,并将Redux分派映射为React prop回调,在需要时将所有props注入组件。容器订阅Redux store,并在新的订阅信号到达时向组件注入新的道具,组件使用新道具进行自我更新。组件调用回调道具来更改数据,进而使容器分派操作。关于更多细节,我们有文档。

问题是,我导入了components/SignUp.js,而不是index.js中的containers/SignUp.js。因此index.js中的行
import-SignUp from./components/SignUp'
变为
import-SignUp from./containers/SignUp'
。因为,容器围绕组件形成一个包裹,将Redux状态映射为React props,并将Redux分派映射为React prop回调,在需要时将所有props注入组件。容器订阅Redux store,并在新的订阅信号到达时向组件注入新的道具,组件使用新道具进行自我更新。组件调用回调道具来更改数据,进而使容器分派操作。有关更多详细信息,我们有文档。

您只需像这样编写mapDispatchToProps即可
const SignUpContainer=connect(mapStateToProps,{fetchEmailExists:onEmailChange})(注册)
。关于另一个prop
emailExists
mapstatetops
是否抛出错误?我尝试了你的connect()语句。这并没有解决问题。通常,mapStateToProps不会引发任何错误,而是从注册组件引发上述警告。但是当我更改电子邮件输入框中的值时,会抛出一个
onEmailChange不是函数
错误。在这里,onBlur事件是通过调用onEmailChange函数来处理的,这是未指定的。我发现了问题。我导入了注册组件而不是注册容器,并将其直接传递到index.js中的render函数中。我已经用下面的解决方案发布了一个答案。你可以像这样简单地编写mapDispatchToProps
const SignUpContainer=connect(mapStateToProps,{fetchEmailExists:onEmailChange})(注册)
。关于另一个prop
emailExists
mapstatetops
是否抛出错误?我尝试了你的connect()语句。这并没有解决问题。通常,mapStateToProps不会引发任何错误,而是从注册组件引发上述警告。但是当我更改电子邮件输入框中的值时,会抛出一个
onEmailChange不是函数
错误。在这里,onBlur事件是通过调用onEmailChange函数来处理的,这是未指定的。我发现了问题。我导入了注册组件而不是注册容器,并将其直接传递到index.js中的render函数中。我已经发布了一个答案和下面的解决方案。