我正在使用React和Redux创建一个简单的登录表单。我的app.js是:
app.js
import React from 'react'; import { render } from 'react-dom'; import Input from 'react-toolbox/lib/input'; import {Button, IconButton} from 'react-toolbox/lib/button'; import PropTypes from 'prop-types'; import * as loginAction from '../actions/loginAction'; class Testing extends React.Component { onLoginFormSubmit(event) { event.preventDefault(); this.props.actions.Testing(this.state.username, this.state.password); } handleChange(name, value){ let state = this.state; state[name] = value; this.setState({state}); console.log(name); // cannot read property of null console.log(value); // cannot read property of null } render() { console.log(this.props); return ( <div> <form name="Login" onSubmit={(e) => this.onLoginFormSubmit(e)}> <Input type="text" name="username" value="" placeholder="Email Id" tabIndex="1" onChange={this.handleChange.bind(this, 'username')} /> <Input name="password" value="" placeholder="Password" type="password" tabIndex="2" onChange={this.handleChange.bind(this, 'password')} /> <Button type="submit" className="m-t-20 blue-btn" label="Sign in" tabIndex="3" /> </form> </div> ); } } Testing.propTypes = { loginAction: PropTypes.object.isRequired, }; function mapStateToProps(state, ownProps) { return { loginResponse: state.loginResponse }; } function mapDispatchToProps(dispatch) { return { actions: bindActionCreators(loginAction, dispatch) } } export default connect(mapStateToProps, mapDispatchToProps)(Testing);
loginAction.js文件为:
export function loginError(error){ return { error, type: LOGIN_FAILED }; } export function loginSuccess(response){ return dispatch => { dispatch({ response, type: LOGIN_SUCCESS}); }; } export function loginRequest(username, password){ const user = {username: username, password: password}; return { user, type: LOGIN_ATTEMPT }; } export function login(username, password) { console.log("User Data: ", username, password); return dispatch => fetch('url', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ username: username, password: password }), }) .then(response => { console.log("I'm here"); if(response.status >= 200 && response.status < 300){ console.log("Response; ", response); dispatch(loginSuccess(response)); } else { const error = new Error(response.statusText); error.response = response; dispatch(loginError()); throw error; } }) .catch(error => { console.log('Request Failed: ', error);}); }
而loginReducer.js文件是:
import { LOGIN_SUCCESS, LOGIN_FAILED, LOGIN_ATTEMPT } from '../actions/loginAction'; import Immutable from 'immutable'; const initialState = new Immutable.Map({ username: '', password: '', isLoggingIn: false, isLoggedIn: false, error: null }); export default function user(state = initialState, action){ switch (action.type){ case LOGIN_ATTEMPT: console.log("LOGIN_ATTEMPT: ",action.user); return state.merge({ isLoggingIn: true, isLoggedIn: false, username: action.user.username, password: action.user.password }); case LOGIN_FAILED: console.log("LOGIN_FAILED: "); return state.merge({ error: action.error, isLoggingIn: false, isLoggedIn: false }); case LOGIN_SUCCESS: console.log("LOGIN_SUCCESS: ",action); return state.merge({ error: null, isLoggingIn: false, isLoggedIn: true }) break; default: return state; } }
运行页面时,出现以下错误:道具类型失败:道具在中actions被标记为必需Testing,但其值为undefined。另外,handleChange方法会引发以下错误:Uncaught TypeError: Cannot set property 'username' of null。
actions
Testing
undefined
handleChange
Uncaught TypeError: Cannot set property 'username' of null
更新: 我的store.js代码是:
import { createStore, applyMiddleware } from 'redux'; import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import user from '../reducers/loginReducer'; const store = createStore( user, applyMiddleware(thunk) ); var routes =( <Provider store={store}> <Router history={browserHistory}> <Route path="/" component={Main}> <Route path="/testing" component={Testing}> </Router> </Provider> );
我现在不想使用redux-form。
该函数handleChange应该仅获取一个事件作为参数。 handleChange(e)此事件附加到目标元素,因此您可以通过e.target.value; 访问其值。 如此说来,不要bind在render函数中使用处理程序。在中进行操作,constructor因为它将handler在每次render调用时创建的新实例。对性能不利。至于redux流程,您应该使用connect。 export default connect(mapStateToProps, mapDispatchToProps)(Testing)。 编辑 再次查看您的代码后,除了您没有使用connect过将组件连接到的事实之外,您还将redux错误的对象映射到mapDispatchToProps。 在此代码中,您正在使用loginAction:
handleChange(e)
e.target.value
bind
render
constructor
handler
redux
connect
export default connect(mapStateToProps, mapDispatchToProps)(Testing)
mapDispatchToProps
loginAction
function mapDispatchToProps(dispatch) { return { actions: bindActionCreators(loginAction, dispatch) } }
但是,您从未导入过它,而是使用了名称导入: import { loginSuccess, loginRequest, login } from '../actions/loginAction'; 导入所有内容并将其传递给的一种可能方法mapDispatchToProps是: import * as loginAction from '../actions/loginAction'; 您犯的另一个错误是在上命名了该对象的名称不同propTypes,actions而没有 为其命名。loginAction
import { loginSuccess, loginRequest, login } from '../actions/loginAction';
import * as loginAction from '../actions/loginAction';
propTypes
Testing.propTypes = { actions: PropTypes.object.isRequired, };
您将需要相同的名称:
Testing.propTypes = { loginAction: PropTypes.object.isRequired, };
再一次不要忘记connect!