Javascript 能不能“a”;减速机;在Redux中,是否默认返回初始状态和默认值?

Javascript 能不能“a”;减速机;在Redux中,是否默认返回初始状态和默认值?,javascript,redux,Javascript,Redux,我在学校学习Redux,因此我们使用测试来确保通过基准测试,以帮助我们理解构建模块 我已经完成了创建Reducer函数的部分,我几乎完成了\o/,但是我无法通过一个测试 1) 默认情况下返回初始状态 在控制台下面吐出来的是 默认情况下,Reducer返回初始状态: AssertionError:应为未定义的对象 在上下文中。(测试/修订规范js:103:49) 我认为这是因为测试处理了一个人应该负责的一些问题,例如导入、创建动作类型等,但不是全部。也许我错过了考试没有提供的东西 无论如何,这是我

我在学校学习Redux,因此我们使用测试来确保通过基准测试,以帮助我们理解构建模块

我已经完成了创建
Reducer
函数的部分,我几乎完成了
\o/
,但是我无法通过一个测试

1) 默认情况下返回初始状态

在控制台下面吐出来的是

默认情况下,Reducer返回初始状态:

AssertionError:应为未定义的对象 在上下文中。(测试/修订规范js:103:49)

我认为这是因为测试处理了一个人应该负责的一些问题,例如导入、创建动作类型等,但不是全部。也许我错过了考试没有提供的东西

无论如何,这是我的reducer文件:

import pet from "../components/PetPreview";
import { createStore } from "redux";

import { adoptPet, previewPet, addNewDog, addNewCat } from "./action-creators";
// ACTION TYPES
const PREVIEW_PET = "PREVIEW_PET";
const ADOPT_PET = "ADOPT_PET";
const ADD_NEW_DOG = "ADD_NEW_DOG";
const ADD_NEW_CAT = "ADD_NEW_CAT";


// INTITIAL STATE
const initialState = {
  dogs: [
    {
      name: "Taylor",
      imgUrl: "src/img/taylor.png"
    },
    {
      name: "Reggie",
      imgUrl: "src/img/reggie.png"
    },
    {
      name: "Pandora",
      imgUrl: "src/img/pandora.png"
    }
  ],
  cats: [
    {
      name: "Earl",
      imgUrl: "src/img/earl.png"
    },
    {
      name: "Winnie",
      imgUrl: "src/img/winnie.png"
    },
    {
      name: "Fellini",
      imgUrl: "src/img/fellini.png"
    }
  ]
// These dogs and cats are on our intial state,
// but there are a few more things we need!
};


export default function reducer(prevState = initialState, action) {
  var newState = Object.assign({}, prevState)

  console.log('initialState', typeof initialState)
  switch (action.type) {

    case PREVIEW_PET:
      // console.log('newState', newState)
      return Object.assign({}, prevState, {
        petToPreview: action.pet
      });
      break
    case ADOPT_PET:
      return Object.assign({}, prevState, {
        petToAdopt: action.pet
      });
      break
    case ADD_NEW_DOG:
      // console.log('action', action.dog)
      // console.log('prevState.dogs', prevState.dogs)
      newState.dogs = prevState.dogs.concat([action.dog])
      return newState;
      break
    case ADD_NEW_CAT:
      // console.log('action', action.dog)
      // console.log('prevState.dogs', prevState.dogs)
      newState.cats = prevState.cats.concat([action.cat])
      return newState;
      break;
    default:
      return prevState;

  }
  return initialState
}
正如您在
开关
块后看到的,我返回
初始状态
难道不是这样吗

下面是
redux.spec.js
文件:

import { expect } from "chai";
import { createStore } from "redux";

// You will write these functions
import {
  previewPet,
  adoptPet,
  addNewDog,
  addNewCat
} from "../src/store/action-creators";
import reducer from "../src/store/reducer";

const DOGS = [
  {
    name: "Taylor",
    imgUrl: "src/img/taylor.png"
  },
  {
    name: "Reggie",
    imgUrl: "src/img/reggie.png"
  },
  {
    name: "Pandora",
    imgUrl: "src/img/pandora.png"
  }
];

const CATS = [
  {
    name: "Earl",
    imgUrl: "src/img/earl.png"
  },
  {
    name: "Winnie",
    imgUrl: "src/img/winnie.png"
  },
  {
    name: "Fellini",
    imgUrl: "src/img/fellini.png"
  }
];

function getRandomPet(pets) {
  return pets[Math.floor(Math.random() * pets.length)];
}

describe("Action creators", () => {
  describe("previewPet", () => {
    it("returns properly formatted action", () => {
      const pet = getRandomPet(DOGS);

      expect(previewPet(pet)).to.be.deep.equal({
        type: "PREVIEW_PET",
        pet: pet
      });
    });
  });

  describe("adoptPet", () => {
    it("returns properly formatted action", () => {
      const pet = getRandomPet(DOGS);

      expect(adoptPet(pet)).to.be.deep.equal({
        type: "ADOPT_PET",
        pet: pet
      });
    });
  });

  describe("addNewDog", () => {
    it("returns properly formatted action", () => {
      const pet = getRandomPet(DOGS);

      expect(addNewDog(pet)).to.be.deep.equal({
        type: "ADD_NEW_DOG",
        dog: pet
      });
    });
  });

  describe("addNewCat", () => {
    it("returns properly formatted action", () => {
      const pet = getRandomPet(CATS);

      expect(addNewCat(pet)).to.be.deep.equal({
        type: "ADD_NEW_CAT",
        cat: pet
      });
    });
  });
}); // end Action creators

describe("Reducer", () => {
  let store;

  beforeEach("Create the store", () => {
    // creates a store (for testing) using your (real) reducer
    store = createStore(reducer);
  });

  it("returns the initial state by default", () => {
    // In addition to dogs and cats, we need two more fields
    expect(store.getState().petToPreview).to.be.an("object");
    expect(store.getState().petToAdopt).to.be.an("object");
  });

  describe("reduces on PREVIEW_PET action", () => {
    it("sets the action's pet as the petToPreview on state (without mutating the previous state)", () => {
      const prevState = store.getState();

      const pet = getRandomPet(DOGS);
      const action = {
        type: "PREVIEW_PET",
        pet: pet
      };
      store.dispatch(action);

      const newState = store.getState();

      // ensures the state is updated properly - deep equality compares the values of two objects' key-value pairs
      expect(store.getState().petToPreview).to.be.deep.equal(pet);
      // ensures we didn't mutate anything - regular equality compares the location of the object in memory
      expect(newState.petToPreview).to.not.be.equal(prevState.petToPreview);
    });
  });

  describe("reduces on ADOPT_PET action", () => {
    it("sets the action's pet as the petToAdopt on state (without mutating the previous state)", () => {
      const prevState = store.getState();

      const pet = getRandomPet(DOGS);
      const action = {
        type: "ADOPT_PET",
        pet: pet
      };
      store.dispatch(action);

      const newState = store.getState();

      expect(newState.petToAdopt).to.be.deep.equal(pet);
      expect(newState.petToAdopt).to.not.be.equal(prevState.petToAdopt);
    });
  });

  describe("reduces on ADD_NEW_DOG action", () => {
    it("adds the new dog to the dogs array (without mutating the previous state)", () => {
      const prevState = store.getState();

      const pet = getRandomPet(DOGS);
      const action = {
        type: "ADD_NEW_DOG",
        dog: pet
      };
      store.dispatch(action);

      const newState = store.getState();

      expect(newState.dogs.length).to.be.equal(prevState.dogs.length + 1);
      expect(newState.dogs[newState.dogs.length - 1]).to.be.deep.equal(pet);
      expect(newState.dogs).to.not.be.equal(prevState.dogs);
    });
  });

  describe("reduces on ADD_NEW_CAT action", () => {
    it("adds the new cat to the cats array (without mutating the previous state)", () => {
      const prevState = store.getState();

      const pet = getRandomPet(CATS);
      const action = {
        type: "ADD_NEW_CAT",
        cat: pet
      };
      store.dispatch(action);

      const newState = store.getState();

      expect(newState.cats.length).to.be.equal(prevState.cats.length + 1);
      expect(newState.cats[newState.cats.length - 1]).to.be.deep.equal(pet);
      expect(newState.cats).to.not.be.equal(prevState.cats);
    });
  });

  describe("handles unrecognized actions", () => {
    it("returns the previous state", () => {
      const prevState = store.getState();

      const action = {
        type: "NOT_A_THING"
      };
      store.dispatch(action);

      const newState = store.getState();

      // these should be the same object in memory AND have equivalent key-value pairs
      expect(prevState).to.be.an("object");
      expect(newState).to.be.an("object");
      expect(newState).to.be.equal(prevState);
      expect(newState).to.be.deep.equal(prevState);
    });
  });
}); // end Reducer

提前谢谢

switch语句中的所有路径都会导致一个
返回
,这意味着倒数第二行的
返回初始状态
是不可访问的。 另外,您的
newState
只不过是
prevState
的克隆,没有必要。 删除它,并为switchcase添加一个helper函数,再加上一些es6 spread love,您的代码就变得

const switchcase = cases => defaultValue => key =>
  (key in cases ? cases[key] : defaultValue);
const reducer = (state = initialState, action) =>
  switchcase({
    [PREVIEW_PET]: { ...state, petToPreview: action.pet },
    [ADOPT_PET]: { ...state, petToAdopt: action.pet },
    [ADD_NEW_DOG]: { ...state, dogs: [...state.dogs, action.dog] },
    [ADD_NEW_CAT]: { ...state, cats: [...state.cats, action.cat] },
  })(state)(action.type);
所有的混乱都消失了,很明显问题在于,如果
action.type==undefined
,代码返回
initialState
对象。您的
initialState
对象只包含
dogs
cats
属性,而您的测试预期会有
petToPreview
petToAdopt
属性


您可以在
初始状态中添加这些属性
,也可以根据需要的功能更改测试。

默认情况下是否应该返回上一个状态?默认情况下,reducer不关心操作,只返回其当前状态,在您的示例中为prevState。

在测试用例中,其中一个测试用例默认表示

it("returns the initial state by default", () => {
    // In addition to dogs and cats, we need two more fields
    expect(store.getState().petToPreview).to.be.an("object");
    expect(store.getState().petToAdopt).to.be.an("object");
  });
这意味着必须在初始阶段将petTpPreview和petToAdapt protery连接到商店。这可以通过将这两个对象添加到状态中来实现,如下所示

// INTITIAL STATE
const initialState = {
  petToPreview:{},
  petToAdopt: {},
  dogs: [
    {
      name: "Taylor",
      imgUrl: "src/img/taylor.png"
    },
    {
      name: "Reggie",
      imgUrl: "src/img/reggie.png"
    },
    {
      name: "Pandora",
      imgUrl: "src/img/pandora.png"
    }
  ],
  cats: [
    {
      name: "Earl",
      imgUrl: "src/img/earl.png"
    },
    {
      name: "Winnie",
      imgUrl: "src/img/winnie.png"
    },
    {
      name: "Fellini",
      imgUrl: "src/img/fellini.png"
    }
  ]
// These dogs and cats are on our intial state,
// but there are a few more things we need!
};

希望有帮助

嘿,我不能理解确切的问题,你想默认返回初始状态吗?如果是,发生了什么,你能解释一下吗further@mindaJalaj现在发生的事情似乎是最后一次没有通过的测试。本质上,默认情况下,
返回初始状态
未通过。我认为@jaihindhreddy很好地回答了这个问题,它有效吗?老实说,我没有尝试过。我读过了,有些结论是不正确的(尽管在我现在的代码中需要newState变量)。我想我宁愿有人帮我写代码,而不是重写代码。有一些伟大的洞察力,我很欣赏这只手,但似乎这是一个令人眼花缭乱的练习,而不是在教学中。就像没有太多的解释和教学,这是一个很好的回答问题的标志。此外,使用诸如“显而易见”和“杂乱无章”之类的词似乎有点过分,因为我说我确实对它投了“赞成票”。嘿,仅仅因为我不明白,并不意味着其他人可能不认为它是金子……那是我的朋友!真不敢相信这么简单!实际上它说的是,//这些狗和猫处于我们的初始状态,//但我们还需要一些东西作为提示!另外,我认为这是一种心理上的转变,就像你刚才演示的那样,在React和Redux中按照正常的方式保存状态,而不是保存状态!非常感谢。不客气。希望你喜欢这个答案,一切都很清楚。真的!水晶!