【问题标题】:Many components with the same reducer but different initial state许多组件具有相同的减速器但初始状态不同
【发布时间】:2019-12-01 10:29:48
【问题描述】:

我通过创建一个小型 RPG 游戏来测试 Redux。

我有一个名为 Monster 的组件,它在地图上移动。位置、方向和 spriteLocation 由 store 控制。怪物减速器是这样的:

const intialState = {
   position: [0,360],
   spriteLocation: '0px 80px',
   direction: 'EAST',
   walkIndex : 0
}

const monsterReducer = (state = intialState, action) => {
   switch(action.type){
       case 'MOVE_MONSTER':
           return {
               ...action.payload
           }
       default:
           return state
   }
}

export default monsterReducer

动作是这样分派的:

import store from '../../config/store'
import {SPRITE_SIZE, MAP_WIDTH, MAP_HEIGHT} from '../../config/constants'

export default function handleMovement(monster){

    //APPEL AU DEPLACEMENT TOUTES LES X secondes
    // setInterval(handleMove(store.getState().monster.direction), 500);
    setInterval(() => {
        handleMove(store.getState().monster.direction)
      }, 300);

    function handleMove(direction){
        switch(direction){
            case 'WEST':
                return attemptMove('WEST')
            case 'EAST':
                return attemptMove('EAST')
            case 'NORTH':
                return attemptMove('NORTH')
            case 'SOUTH':
                return attemptMove('SOUTH')
            default:
        }
    }

    function attemptMove(direction){
        const oldPos = store.getState().monster.position
        const newPos = getNewPosition(oldPos,direction)
        if(observeBoundaries(newPos) && observeImpassable(newPos)){
            dispatchMove(direction, newPos)
        }else{
            switch(direction){
                case 'WEST':
                    return attemptMove('EAST')
                case 'EAST':
                    return attemptMove('WEST')
                case 'NORTH':
                    return attemptMove('SOUTH')
                case 'SOUTH':
                    return attemptMove('NORTH')
                default:
            }
        }
    }

    //UPDATE DE LA POSITION
    function getNewPosition(oldPos, direction){
        switch(direction){
            case 'WEST':
                return [oldPos[0]-SPRITE_SIZE, oldPos[1]]
            case 'EAST':
                return [oldPos[0]+SPRITE_SIZE, oldPos[1]]
            case 'NORTH':
                return [oldPos[0], oldPos[1]-SPRITE_SIZE]
            case 'SOUTH':
                return [oldPos[0], oldPos[1]+SPRITE_SIZE]
            default:
        }        
    }

    function observeBoundaries(newPos){
        //SI ON EST DANS LA MAP ON RETOURNE TRUE SINON FALSE
        return (newPos[0] >= 0 && newPos[0] <= MAP_WIDTH-SPRITE_SIZE) &&
                (newPos[1] >= 0 && newPos[1] <= MAP_HEIGHT-SPRITE_SIZE)
    }

    function observeImpassable(newPos){
        //TEST DES OBSTACLES
        const tiles = store.getState().map.tiles
        const y = newPos[1] / SPRITE_SIZE
        const x = newPos[0] / SPRITE_SIZE
        const nextTile = tiles[y][x]
        return  nextTile < 5
    }

    function getWalkIndex(){
        const walkIndex = store.getState().monster.walkIndex
        return walkIndex >= 4 ? 0 : walkIndex+1
    }

    function getSpriteLocation(direction, walkIndex){
        switch (direction){
            case 'EAST' :
                return `${SPRITE_SIZE*walkIndex}px ${SPRITE_SIZE*2}px`
            case 'SOUTH' :
                return `${SPRITE_SIZE*walkIndex}px ${SPRITE_SIZE*0}px`
            case 'WEST' :
                return `${SPRITE_SIZE*walkIndex}px ${SPRITE_SIZE*3}px`
            case 'NORTH' :
                return `${SPRITE_SIZE*walkIndex}px ${SPRITE_SIZE*1}px`
            default:

        }
    }

    //DISPATCH DE LA NOUVELLE POSITION ET DIRECTION POUR ANIMATION DU PERSO AU STORE
    function dispatchMove(direction, newPos){
        const walkIndex = getWalkIndex()
        store.dispatch({
            type: 'MOVE_MONSTER',
            payload: {
                position: newPos,
                direction,
                walkIndex,
                spriteLocation : getSpriteLocation(direction, walkIndex)
            }
        })
    }

    return  monster
}

我想创建另一个 Monster 组件,但初始状态不同,但使用相同的 reducer。

也许使用 reducer 不是一个好的解决方案?

【问题讨论】:

    标签: reactjs redux react-redux


    【解决方案1】:

    Redux 用于在组件内共享状态,而不是保存单个组件状态。所以在这种情况下,怪物组件可以有自己的状态,或者如果仍然需要减速器,则必须更改减速器的结构。

    const intialState = {
       monsters: {
       }
    }
    
    const monsterReducer = (state = intialState, action) => {
       switch(action.type){
           case 'MOVE_MONSTER':
               return {
                   ...action.payload
               }
           default:
               return state
       }
    }
    
    export default monsterReducer
    

    所以当一个怪物被注册时,你可以在同一个减速器中初始化怪物。 即

    registerMonster(id) - 新怪物动作时

    减速器

    case "REGISETER_MONSTER":
        return {
           ...state,
           [action.payload.id]: {
               position: [0,360],
               spriteLocation: '0px 80px',
               direction: 'EAST',
               walkIndex : 0
           }
        }
    
    

    每个怪物的 id 应该是唯一的,然后更新逻辑也会改变,你必须传递怪物的 id 并相应地更新。

    【讨论】:

    • 感谢您的帮助。我理解其中的逻辑,但我不明白我在注册每个怪物时可以在哪里设置它们的初始状态。
    • 您计划在旅途中动态创建怪物的地方,或者总是有 N 个怪物。
    • 好的,谢谢,我觉得我的 React 水平太低,无法直接理解,所以我会根据你的帮助尝试一下。再次感谢!
    • 没关系,我只是用类组件替换了我的功能组件 Monster 并且不使用 Redux .. 感谢您的帮助
    猜你喜欢
    • 1970-01-01
    • 2017-11-22
    • 2020-09-13
    • 2019-05-11
    • 1970-01-01
    • 1970-01-01
    • 2013-08-10
    • 1970-01-01
    • 2020-05-10
    相关资源
    最近更新 更多