简体   繁体   中英

Change state's array without changing the whole state (REACT / REDUX)

I got a list of things to buy (for a little game i'm making with React) who is an array. It's in a state called "Market". And i have the other one, where i want to randomise all the value and stock them in another state.

This is my Market list:

let marketList = [
  {"name": 'product name', "qty": 0, "minPrice": 10, "maxPrice": 100, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 30, "maxPrice": 200, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 100, "maxPrice": 1500, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 200, "maxPrice": 4000, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 50, "maxPrice": 6000, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 1, "maxPrice": 400, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 60, "maxPrice": 3450, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 2, "maxPrice": 120, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 8, "maxPrice": 600, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 120, "maxPrice": 3200, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 35, "maxPrice": 100, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 300, "maxPrice": 12000, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false},
  {"name": 'product name', "qty": 0, "minPrice": 1, "maxPrice": 80, "currentPrice": 0, "historyPrice": [], "historyQty": [], "available": false}
];

I want to randomise all the value in it and store the randomised list in a state called "Tomorrow" to be able to gives hints about the next prices. This is my helpers to randomise the lists.

export function randomiseMarketList(list, day = 0){
  for(let i = 0; i < list.length; i++) {
    let item = list[i];
    let historyQtylength = item.historyQty.length;
    let random = randomAlgo(day);

    item.currentPrice = Math.floor(Math.random() * (item.maxPrice - item.minPrice)) + item.minPrice;
    item.qty = random;
    item.available = !(day == 0 || item.qty < 1);

    item.historyPrice.push(item.currentPrice);
    item.historyQty.push(item.qty);
  } 
  return list;
}

function randomAlgo(day) {
  let quart = Math.floor(Math.random() * 4);
  let multiple = Math.floor(Math.random() * 10);
  let maxQuart = Math.floor(Math.random() * (quart * multiple * day));
  let minQuart = Math.floor(Math.random() * (quart * multiple));
  return Math.floor(Math.random() * (maxQuart - minQuart)) + minQuart;
}

And this is my Tomorrow reducer:

import { ACTIONS } from '../utils/consts';
import { randomiseMarketList } from '../utils/helpers';

var initialState = {
  currentPlaceList: []
};

export function tomorrow(state = initialState, action = '') {
  switch (action.type) {

    case ACTIONS.BUILD_TOMORROW_LIST:
      console.log(action);
      let listToRandom = action.list.slice();
      let randomactionList = randomiseMarketList([...listToRandom], action.day);
      console.log(randomactionList);
      let newList = Object.assign({}, state, { currentPlaceList: randomactionList });
      return newList;

    default:
      return state;
  }
}

As you can see in my ACTIONS.BUILD_TOMORROW_LIST, i console log the action to check the value at first, and after i log the randomised list, who always has the same values. I don't understand here why they have the same values if i changed them.

I thought it was because the array was the absolute same and i changed the state directly (don't understand why). I passed the list as a new array built by the values and the spread operator, doesn't work either. I tried to create a copy of this array, doesn't work too.

The list in the tomorrow will be used to replace the current Market's list when we click on the "stay here" action.

handleStayHere(e) {
    const { dispatch, status, tomorrow, market } = this.props;
    dispatch( MarketActions.changeWholeList(tomorrow.currentPlaceList) );
    dispatch( StatusActions.changeDay( status.day + 1 ) );
    dispatch( TomorrowActions.buildTomorrowList([...market], status.day + 1) );
  }

The MarketActions.changeWholeList action works well, but i can't store correctly the tomorrow list.

Thank you for your help!

Looks like you don't change list's elements but mutate them in randomizer. This could lead to bizarre behaviour (debugged problem with this yesterday =)) ) I think it's better to map list values to new objects in randomiseMarketList , so you don't need to worry about item objects being the same and array slicing — it will be just plainly another object reference.

randomiseMarketList(list, day = 0){
  return list.map(item => {
    //it case there's another meaningful properties in item
    ...item,
    qty: randomAlgo(day),
    currentPrice: Math.floor(Math.random() * (item.maxPrice - item.minPrice)) + item.minPrice,
    available: !(day == 0 || item.qty < 1),
    historyPrice: [...item.historyPrice, item.currentPrice],
    historyQty: [...item.historyQty, item.qty],
})

And then in reducer

function tomorrow(state = initialState, action) {
  switch (action.type) {
    case ACTIONS.BUILD_TOMORROW_LIST:
      const currentPlaceList = randomiseMarketList(action.list, action.day);
      return {...state, currentPlaceList}

    default:
      return state;
  }
}

Another one, in reducer you're slicing array and then destructure it to another array — this looks like double work with no outcome.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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