OctaviaLo
OctaviaLo

Reputation: 1396

Handling separate async calls for items in Redux store

I have some racing bees. In my redux store, they are objects in an array with a name property and a likelihood property. For each bee, I would like to calculate its likelihood of winning. The calculating algorithm is async. When I start the calculations of all the bees, the bee's likelihood property should have a value of 'calculating', when the bee's calculation has completed, the likelihood property should show a number.

I have a function generateBeeWinLikelihoodCalculator which cannot be modified.

Right now, my code does not calculate the likelihood of winning for the bees separately and I am at a loss for how best to achieve this. I thought of dispatching the calcultingLikelihood function to each bee instance and calling it in the reducer, but then how do I get it to return 'calculating...' first and then when the setTimeout has run, to then return the value?

let state = {bees:[{name: 'marie'},{name: 'john'}]}

const reducer = (state, action) => {
	switch (action.type) {
  	case 'FETCH_BEES':
    	return {
      	...state,
        bees: action.bees,
      }
    case 'RUN_CALCULATIONS':
    	return {
      	...state,
        bees: state.bees.map(bee => {
        	bee.likelihood = action.likelihood
          return bee
        })
      }
     case 'DISPLAY_CALCULATIONS':
     	return {
      	...state,
        bees: state.bees.map(bee => {
        	bee.likelihood = action.likelihood
          return bee
        })
      }
     default: return state
  }
}

const runCalculations = (likelihood) => ({
	type: 'RUN_CALCULATIONS',
  likelihood,
})

const displayCalculations = (likelihood) => ({
	type: 'DISPLAY_CALCULATIONS',
  likelihood,
})

const store = {
	dispatch: (action) => {
  	state = reducer(state,action)
  	return state
  },
  getState: () => {
  	return state
  }
}

//this calculator cannot be modified
const generateBeeWinLikelihoodCalculator = () => {
  var delay = 1000 + Math.random() * 1000;
  var likelihoodOfAntWinning = Math.random();

  return function(callback) {
    setTimeout(function() {
      callback(likelihoodOfAntWinning)
    }, delay);
  };
}

const calculatingLikelihood = () => {
  store.dispatch(runCalculations('calculating...'))
  console.log(JSON.stringify(store.getState()))
	const callback = (likelihoodOfBeeWinning) => {
  	store.dispatch(displayCalculations(likelihoodOfBeeWinning))
  	console.log(JSON.stringify(store.getState()))
  }
  return generateBeeWinLikelihoodCalculator()(callback)
}

calculatingLikelihood()

Upvotes: 0

Views: 72

Answers (1)

chautelly
chautelly

Reputation: 467

I would give the bees an id property as well and store them as a map of bees by id vs. an array of bees. This makes updating individual bees in state easier.

You can make use of promises or async/await as well.

So state becomes:

let state = {bees: { 1: { id: 1, name: 'marie' }, 2: { id: 2 name: 'john'} }

// Grab the list of Bees
const bees = store.getState().bees

// Work on each bee and update it individually
Object.values(bees).forEach(async bee => {
  const likelihood = await calculate(bee)
  store.dispatch({ type: 'UPDATE_BEE', payload: { ...bee, likelihood } })
})

// Or you could wait for all calculations to resolve before updating state
const promises = Object.values(bees).map(async bee => {
  const likelihood = await calculate(bee)
  return { ...bee, likelihood }
})

Promise.all(promises).then(bees => {
  store.dispatch({ type: 'UPDATE_BEES', payload: _.keyBy(bees, 'id') })
})

Upvotes: 1

Related Questions