Strange error using reduce method in React

I’m working on a challenge as part of a take-home interview challenge and I’ve run into a really strange error with the reduce method. I’m rendering a list of products and I have to label the best-seller based on a “units sold” property. I’ve tried using the reduce method as follows:

let bestNum = this.props.wines.reduce((a, b) => {
     return Math.max(a.unitsSold, b.unitsSold);
});

This should work as I’ve tested it using a mock array in a repl. However when using this with React I get the error: “React.createElement: type is invalid”. I realized that it’s giving me this error because of the missing argument after the callback but from what I’ve read in the documentation, this argument is optional. So why won’t it play nice with React?

Aren’t props immutable?

I don’t see how calling reduce would result in an error in the createElement method. Are you using bestNum in the render method?

Yeah I’m using it in the render method. I’m only getting this error when omitting the accumulator argument. If I were to put “0” as the accumulator, the error disappears and I get a result, just not a result I want of course.
I did find a workaround in the meanwhile, however by doing this:

let bestNum = this.props.wines.map((wine) => {
      return wine.unitsSold;
});
bestNum = Math.max(...bestNum)

It’s a bit more verbose than my original intention but It will do for now, I suppose.

let bestNum = this.props.wines.reduce((a, b) => {
     return Math.max(a.unitsSold, b.unitsSold);
});

Here you have a as the accumulator and b as the element. I find it easier to think about what I’m doing when I mark them explicitly as eg; (acc, elt).

Your accumulator will just be a number, so I don’t think a.unitsSold will make sense. Is that right?

let bestNum = this.props.wines.reduce((acc, elt) => {
     return Math.max(acc, elt.unitsSold);
});

Written like this, I think the initial accumulator is optional - previously, you were trying to access a property on an undeclared var (I think) which is probably what was causing the issue.

2 Likes

…in addition to @r1chard5mith answer:
js .reduce is actually two functions glued together - fold and reduce.

reduce reduces multiple entities into one of same type, think about array of numbers into number, or array of strings into one string. To do that, you don’t actually need initial accumulator value, since first element can be used as one.* **

fold folds one entity into another - array of numbers into array of strings, one number or even object. To do that, you need to provide some initial value, because function can’t figure it for itself.

https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/list.fold['t,'state]-function-[fsharp]
https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/list.reduce['t]-function-[fsharp]

In your case - you folding collection of objects into a number.

(*)

Except empty arrays, which will throw an exception. So, if you array never null or empty, you can omit initial value.

(**)
sum(a, b) = a + b
[1, 2, 3].reduce(sum) == [2, 3].reduce(sum, 1) == [1, 2, 3].reduce(sum, 0)