繁体   English   中英

Redux中的“ Reducer”能否默认返回初始状态和默认值?

[英]Can a “Reducer” in Redux return an initial state by default AND a default value?

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

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

1)默认返回初始状态

在控制台下方吐口水...

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

AssertionError:期望未定义为Context对象。 (试验/ redux.spec.js:103:49)

我认为这是因为测试处理了一些可能引起的问题,例如导入,创建操作类型等。但并非全部。 所以也许我缺少测试未提供的内容?

无论如何,这是我的减速器文件:

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
}

如您所见,在switch块之后,我正在返回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语句中的所有路径均导致return ,这意味着倒数第二行上的return initialState无法访问。 另外,您的newState只是prevState的克隆, prevState是不必要的。 删除它,并为开关盒添加一些辅助功能,并结合一些es6传播爱,您的代码将

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对象仅包含dogscats属性,而您的测试希望有petToPreviewpetToAdopt属性。

您可以在initialState添加这些属性,也可以根据所需的功能更改测试。

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

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属性。 可以通过将以下两个作为对象添加到状态中来完成此操作。

// 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!
};

希望能帮助到你!

默认情况下,您不应该返回以前的状态吗? 默认情况下,reducer不关心该操作,而只是返回其当前状态,在您的情况下为prevState。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM