我正在使用React和Redux创建一个简单的登录表单。我的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
。
更新:我的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。
答案 0 :(得分:1)
函数handleChange
应该只将一个事件作为参数
handleChange(e)
此事件附加到目标元素,因此您可以通过e.target.value
访问其值;
话虽如此,请bind
方法中不要render
hendlers。在constructor
中执行此操作,因为它会在每个handler
调用中创建render
的新实例。表现不好。
对于redux
流程,您应该使用connect
export default connect(mapStateToProps, mapDispatchToProps)(Testing)
。
的修改
再看一下您的代码,除了您没有使用connect
将组件连接到redux
之外,您将错误的对象映射到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
Testing.propTypes = {
actions: PropTypes.object.isRequired,
};
您需要相同的名称:
Testing.propTypes = {
loginAction: PropTypes.object.isRequired,
};
再次不要忘记connect
!!
答案 1 :(得分:0)
我认为您需要将组件连接到redux。
import { connect } from 'react-redux'
// your code
export default connect(mapStateToProps, mapDispatchToProps)(Testing)
不要忘记在课前删除export default
。
编辑:如果您计划修改组件的本地状态,请使用setState
。