开发者问题收集

失败的道具类型:prop“ action”在``测试''中按要求标记,但其值是``未定义''

2017-05-12
6240

我正在使用 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;

  }
}

运行页面时出现此错误:失败的 prop 类型:prop actionsTesting 中被标记为必需,但其值为 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。

2个回答

函数 handleChange 应该只获取一个事件作为参数。
handleChange(e) 此事件附加到目标元素,因此您可以通过 e.target.value 访问其值;
话虽如此,不要在 render 函数中 bind 处理程序。在 constructor 中执行此操作,因为它会在每次 render 调用时创建 handler 的新实例。这对性能不利。 至于 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 !!

Sagiv b.g
2017-05-12

我相信您需要将您的组件连接到 redux。

import { connect } from 'react-redux'

 // your code

 export default connect(mapStateToProps, mapDispatchToProps)(Testing)

不要忘记从您的课程前面删除 export default

编辑:如果您打算修改组件的本地状态,请使用 setState

cssko
2017-05-12