React/Redux 在 onClick 事件期间跳过一行

时间:2021-06-25 12:46:56

标签: javascript reactjs react-native redux

我有以下组件负责一些事情

  1. 显示移动
  2. 将 onClick 事件附加到将触发长时间调度的移动 2a.在此调度中,对手移动是从现有对手对象的移动数组中选择的。
  3. 事件侦听器函数将确定谁先进行攻击,然后分派每个攻击者对状态进行适当的更改。

下面的代码在大约 80% 的时间里工作,事实上,它总是适用于至少三个不同的实例(选择一个动作,处理调度,选择另一个,再次调度,等等),但是在三个之后,(通常更多)一行会被跳过。

点击后,processMoves 函数被调用,它将处理步骤 2a 和 3。同样,这几乎总是有效,但有时行 let oppMoveObj = makeOppMoveSelection(opp) 被跳过,破坏它下面的所有内容。我知道它会跳过这一行,因为在那个函数内部,我有一个 debugger 和多个 console.log 语句,它们将在前三次或更多点击中被击中。代码如下

import React, { Component } from 'react';
import { connect } from 'react-redux';
import makeOppMoveSelection from '../../helpers/oppMoveSelection';
import { moveAction } from '../../helpers/moveHelper';
import './Move.css'

// PROPS MEHTODS
const mapStateToProps = (state) => {
    return(
        {battle: state.battle}
    )
}
const mapDispatchToProps = (dispatch) => {
    return({
            chooseMove: (move, props) => processMoves(move, props),
            executeMove: (move, attacker) => dispatch(moveAction(move, attacker)),
            initiateMoveProcess: () => dispatch({type: 'MOVE_SELECTED'}),
            completeMoveprocess: () => dispatch({type: 'MOVE_PROCESS_COMPLETE'})
        })
}
// PROPS METHODS



// This will handle everything battle related after move selection. This includes...
    // 1. Accepts the selected move from the User
    // 2. Selects a move from the Opponent's available moves
    // 3. Determines if they are shocked, they move last
    // 4. Determines if any move has 'move first' effect, if so that move goes first
    // 5. Compares speed to determine which move goes first
    // 6. If any figure has 0 health after any move, the battle ends
    // 7. After the moves are executed, applies any damage from status effects
function processMoves(moveObj, props){
    // Assigns global values
    let opp = props.battle.opp
    let user = props.battle.user

    // Selects a move that the opponent uses
    let oppMoveObj = makeOppMoveSelection(opp)

    // Removes the move selection screen for the message 
    props.initiateMoveProcess()  // ERROR OCCURS HERE

    // If someone is using a move that moves first
    if (moveObj.effect == "move first" && oppMoveObj.effect != "move first"){
        props.executeMove(moveObj, "user")
        props.executeMove(oppMoveObj, "opp")
    }
    else if (oppMoveObj.effect == "move first" && moveObj.effect != "move first"){
        props.executeMove(oppMoveObj, "opp")
        props.executeMove(moveObj, "user")
    }

    // If someone is shocked the other goes first
    else if (opp.status == "shocked" && user.status != "shocked"){
        props.executeMove(moveObj, "user")
        props.executeMove(oppMoveObj, "opp")
    }
    else if (opp.status != "shocked" && user.status == "shocked"){
        props.executeMove(oppMoveObj, "opp")
        props.executeMove(moveObj, "user")
    }

    // Handles everything else
    else{
        if (user.spd >= opp.spd){
            props.executeMove(moveObj, "user")
            props.executeMove(oppMoveObj, "opp")
        }
        else{
            props.executeMove(oppMoveObj, "opp")
            props.executeMove(moveObj, "user")
        }
    }
}

class Move extends Component{


    handleClick = (event, props) => {
        let indexofMove = parseInt((event.target.offsetParent.id.split("e")[1]), 10)
        let selMove = this.props.battle.user.moves[indexofMove]
        this.props.chooseMove(selMove, props)
    }

    render(){
        return(
            // get the index in as a prop from move container.
            // This way, we can access the battle.user.moves and find the move that way for the dispatch. 
            // Meaning, the event would track the id of the div it clicked, and then use that id as the index 
            // of the move in the user.moves array to send in the dispatch and figure out all the damage
            <div className={`MoveCard ${this.alterClassNameBasedOnCoolDown(this.props)}`} id={`MoveCard${this.props.index}`}
                onClick = {(event) => this.handleClick(event, this.props)}>
                <p id="name">{this.props.m.name}</p>
                <p id="type">Type: {this.props.m.type}</p>
                <p id="acc">Accuracy: {this.props.m.acc}</p>
                <p id="dmg">{this.pow_or_heal(this.props.m.dmg)} {this.props.m.dmg}</p>
                <p id="cool">Cooldown: {this.props.m.cool}</p>
            </div>
        )
    }

}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Move)

快速编辑

我的 oppMoveSelection.js 文件看起来像这样...

export default function makeOppMoveSelection(opp){
    let cooled = opp.moves.map( (move) => {
        if (move.tillCooldown == 0){
            return move
        }
    })
    if (opp.hp < 50 ){
        cooled.forEach(element => {
            if (element.dmg < 0){
                return element
            }
        });
    }
    else{
        let len = cooled.length
        let indexSel = Math.floor(Math.random() * len)
        console.log("Inside opp move picker")
        console.log(cooled)
        console.log("Index selected: " + indexSel)
        return opp.moves[indexSel]
    }

}

我真的不知道是什么导致编译器完全跳过一行,而且由于从未定义过 oppMoveObj,我会收到错误 Uncaught TypeError: Cannot read property 'effect' of undefined,即使它之前可以完美运行很多次。有人看到可能出了什么问题吗?

1 个答案:

答案 0 :(得分:0)

如果 HP 低于 50,那些 console.logs 不会被击中,所以我们假设它在这里。

通常,我建议您在 debugger; 函数的第一行中编写 makeOppMoveSelection,然后观察浏览器的开发工具中发生的情况,但这是我的猜测:

代码输入您的 .forEach

        cooled.forEach(element => {
            if (element.dmg < 0){
                return element
            }
        });

并且在某些时候它会执行 return element。但是您假设想要从 return 获得 makeOppMoveSelection。但实际上,它只会从 return 中的箭头函数.forEach。然后该循环继续运行下一次迭代,完成,然后 makeOppMoveSelection 结束,而没有遇到 return 语句。

这是使用 .forEach 的问题,老实说,我再也不会使用该功能了。自 2015 年 ES6 引入 for or 循环以来,这只是一个遗留的产物。

所以改用其中之一:

        for (const element of cooled) {
            if (element.dmg < 0){
                return element
            }
        });

这将如您所愿。

相关问题