TypeError: Cannot read property 'type' of undefined Error before any Components even render

TypeError: Cannot read property 'type' of undefined Error before any Components even render

我的 Redux 应用程序甚至不会呈现第一个组件 (App.js),因为它一直出错。在某些时候,它会在没有任何操作的情况下触发 reducer(如下所示),因此当编译器到达行 switch(action.type) 时,它一直认为操作为空,因此它找不到 type 属性任何地方。事实上,我有一个 console.log 作为函数的第一行,当 App.js 被渲染时立即调用它甚至不会触发,这意味着代码甚至在渲染单个组件之前就中断了.请记住,我在 index.js 中设置了 <Provider /> 标签,它呈现 App.js

------------------------减速器-------------------- ------

const rootReducer = combineReducers({
    battle: manageBattle,
    user: manageUser // Ignore this right now, it's not in any components that are getting rendered
  })
  export default rootReducer
function manageBattle(
    action,
    state={
        figures:{                       // The following figures are temporary as the stats will ne changed during the battle.
            user: {                     // We save the original user stats under the manageUser reducer
                is_user: true,                  // Might be needed. Might not, we'll find out
                name: "",                       // The name of the user figure
                class_type: null,
                id: null,                       // Generated in Rails
                hp: 0,                          // Health
                type: null,                     // Type, one of... TECH, WEAPONRY, SUPERNATURAL, ATHLETIC, NETHER, STEALTH. Each has a different effectiveness on the other
                level: 0,                       // Keeps track of how many fights they have won
                status: "none",                 // Certins moves (generated by Rails) have status effects. This variable holds what effects (if any) are present on the user
                spd: 0,                         // Speed
                atk: 0,                         // Attack
                def: 0,                         // Defense... you get it right?
                sAtk: 0,                        //
                sDef: 0,                        //
                tEffected: 0,                   // How many turns the user has been effected by a status effect. 0 if unaffected 
                image: "N/A",                   // Generated by Rails and used to determine with jpeg to load
                moves: [null]                   // Sets an empty array for the moves and setting that up is gonna suck so I'm avoiding it
            },
            opp: {
                is_user: false,
                name: "",
                class_type: null,
                id: null,                       // See Above
                hp: 0,
                type: null,
                level: 0,
                status: "none",
                spd: 0,
                atk: 0,
                def: 0,
                sAtk: 0,
                sDef: 0,
                tEffected: 0,
                image: "N/A",
                moves: [null]
            }
        },
        battle_details: {
            turns: 0,                           // This will keep track of the turns elapsed
            whoseTurn_id: null,                     // This will be set to 'user', 'opp', or 'none'. 
            this_move_target_id: null,
            prompt: "Welcome"
        }
    }
){
    if (!action){
        console.log("Action is nil")
    }
    switch (action.type) {
        case 'NEW_BATTLE':
        // FETCH NEW BATTLE JSON

        case 'CHANGE_USER_HP':
            // action = {type: "CHANGE_OPP_HP", amount: {Number generated in Event Listener inside of Moves}, effect: {String generated in Event Listener} }
            let effect = action.effect
            let newUserState = applyingStatusEffectandDamage(state, action.amount, effect)
            return {newUserState}

        case 'CHANGE_OPP_HP':
            // action = {type: "CHANGE_OPP_HP", amount: {Number generated in Event Listener inside of Moves}, effect: {String generated in Event Listener} }
            effect = action.effect
            let newOppState = applyingStatusEffectandDamage(state, action.amount, effect)
            return {newOppState}

        case 'COMPLETE_BATTLE':
            // CHANGE PROMPT, RESET USER HP, LEVEL UP
        
        default:
            return state;
    }
};

--------------------App.js--------------------

import { connect } from 'react-redux';
import './App.css';
import BattleCard from './components/containers/BattleCard';
import React, { Component } from 'react';
import CreationContainer from './components/dispatchers/CreationContainer';

class App extends Component {

  intro_or_resume = (props) => {
    console.log(props)
    if (props.user.created === true){
      return(
        <div className="Battle Container">
           <BattleCard />
        </div>
      )
    }
    else{
      return(
        <div className="Create Form">
           <CreationContainer />
        </div>
      )
    }
  }
  testPlease = () => {
    console.log("hello!")
  }
  render() {
    return (
      <div className="Main-Window">
        {this.testPlease()}
        {this.intro_or_resume(this.props)}
      </div>
    )
  }
}
const mapStateToProps = (state) => {
  return { user: state.user }
}

export default connect(mapStateToProps)(App);

this.testPlease() 函数没有被命中,我可以在它被调用时在 reducers 中告诉它 action = nil 因为 if (!action){console.log("Action is nil")} 每次我尝试启动应用程序时都会被命中. npm start 也向我发出了几分钟的警告,但我认为不会影响到这一点;除了浏览器之外,任何地方都没有产生实际错误

您的 reducer 函数需要先排序 state,然后排序 action

const rootReducer = combineReducers({
  battle: manageBattle,
  user: manageUser // Ignore this right now, it's not in any components that are getting rendered
})
export default rootReducer
function manageBattle(
  state={
      figures:{                       // The following figures are temporary as the stats will ne changed during the battle.
          user: {                     // We save the original user stats under the manageUser reducer
              is_user: true,                  // Might be needed. Might not, we'll find out
              name: "",                       // The name of the user figure
              class_type: null,
              id: null,                       // Generated in Rails
              hp: 0,                          // Health
              type: null,                     // Type, one of... TECH, WEAPONRY, SUPERNATURAL, ATHLETIC, NETHER, STEALTH. Each has a different effectiveness on the other
              level: 0,                       // Keeps track of how many fights they have won
              status: "none",                 // Certins moves (generated by Rails) have status effects. This variable holds what effects (if any) are present on the user
              spd: 0,                         // Speed
              atk: 0,                         // Attack
              def: 0,                         // Defense... you get it right?
              sAtk: 0,                        //
              sDef: 0,                        //
              tEffected: 0,                   // How many turns the user has been effected by a status effect. 0 if unaffected 
              image: "N/A",                   // Generated by Rails and used to determine with jpeg to load
              moves: [null]                   // Sets an empty array for the moves and setting that up is gonna suck so I'm avoiding it
          },
          opp: {
              is_user: false,
              name: "",
              class_type: null,
              id: null,                       // See Above
              hp: 0,
              type: null,
              level: 0,
              status: "none",
              spd: 0,
              atk: 0,
              def: 0,
              sAtk: 0,
              sDef: 0,
              tEffected: 0,
              image: "N/A",
              moves: [null]
          }
      },
      battle_details: {
          turns: 0,                           // This will keep track of the turns elapsed
          whoseTurn_id: null,                     // This will be set to 'user', 'opp', or 'none'. 
          this_move_target_id: null,
          prompt: "Welcome"
      }
  }, action
){
  if (!action){
      console.log("Action is nil")
  }
  switch (action.type) {
      case 'NEW_BATTLE':
      // FETCH NEW BATTLE JSON

      case 'CHANGE_USER_HP':
          // action = {type: "CHANGE_OPP_HP", amount: {Number generated in Event Listener inside of Moves}, effect: {String generated in Event Listener} }
          let effect = action.effect
          let newUserState = applyingStatusEffectandDamage(state, action.amount, effect)
          return {newUserState}

      case 'CHANGE_OPP_HP':
          // action = {type: "CHANGE_OPP_HP", amount: {Number generated in Event Listener inside of Moves}, effect: {String generated in Event Listener} }
          effect = action.effect
          let newOppState = applyingStatusEffectandDamage(state, action.amount, effect)
          return {newOppState}

      case 'COMPLETE_BATTLE':
          // CHANGE PROMPT, RESET USER HP, LEVEL UP
      
      default:
          return state;
  }
};

希望这对你有用。