# Refactoring class component to React functional component

**URL:** <https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442>\
**Category:** web dev\
**Created:** [October 28, 2021, 3:28pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442 "2021-10-28T15:28:55Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![pepasteel](https://avatars.discourse-cdn.com/v4/letter/p/59ef9b/32.png) [@pepasteel](https://forum.kirupa.com/u/pepasteel)\
**Post date:** [October 28, 2021, 3:28pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/1 "2021-10-28T15:28:55Z")

</div>

I am a beginner in javascript and react. I’m trying to refactor the class component into a functional one (Rules for Yahtzee game scoring).

**This is class component:**

```auto
/** Rule for Yahtzee scoring.
 *
 * This is an "abstract class"; the real rules are subclasses of these.
 * This stores all parameters passed into it as properties on the instance
 * (to simplify child classes so they don't need constructors of their own).
 *
 * It contains useful functions for summing, counting values, and counting
 * frequencies of dice. These are used by subclassed rules.
 */

 class Rule {
  constructor(params) {
    // put all properties in params on instance
    Object.assign(this, params);
  }
 
 sum(dice) {
    // sum of all dice
    return dice.reduce((prev, curr) => prev + curr);
  }
 
 freq(dice) {
    // frequencies of dice values
    const freqs = new Map();
    for (let d of dice) freqs.set(d, (freqs.get(d) || 0) + 1);
    return Array.from(freqs.values());
  }
 
 count(dice, val) {
    // # times val appears in dice
    return dice.filter(d => d === val).length;
  }
}

/** Given a sought-for val, return sum of dice of that val.
  * Used for rules like "sum of all ones"*/

class TotalOneNumber extends Rule {
  evalRoll = dice => {
    return this.val * this.count(dice, this.val);
  };
}

/** Given a required # of same dice, return sum of all dice.
 * Used for rules like "sum of all dice when there is a 3-of-kind"*/
class SumDistro extends Rule {
  evalRoll = dice => {
    // do any of the counts meet of exceed this distro?
    return this.freq(dice).some(c => c >= this.count) ? this.sum(dice) : 0;
  };
}

/** Check if full house (3-of-kind and 2-of-kind) */
class FullHouse extends Rule {
  evalRoll = dice => {
    const freqs = this.freq(dice);
    return freqs.includes(2) && freqs.includes(3) ? this.score : 0;
  };
}

/** Check for small straights. */
class SmallStraight extends Rule {
  evalRoll = dice => {
    const d = new Set(dice);
    // straight can be 234 + either 1 or 5
    if (
      (d.has(2) && d.has(3) && d.has(4) && d.has(5) && d.has(2)) ||
      d.has(5)
    ) {
      return this.score;
    }
    // or 345 + either 2 or 6
    if ((d.has(3) && d.has(4) && d.has(5) && d.has(2)) || d.has(6)) {
      return this.score;
    }
    return 0;
  };
}

/** Check for large straights. */
class LargeStraight extends Rule {
  evalRoll = dice => {
    const d = new Set(dice);
    // large straight must be 5 different dice & only one can be a 1 or a 6
    return d.size === 5 && (!d.has(1) || !d.has(6)) ? this.score : 0;
  };
}

/** Check if all dice are same. */
class Yahtzee extends Rule {
  evalRoll = dice => {
    // all dice must be the same
    return this.freq(dice)[0] === 5 ? this.score : 0;
  };
}

// ones, twos, etc score as sum of that value
const ones = new TotalOneNumber({ val: 1, description: '1 point per 1' });
const twos = new TotalOneNumber({ val: 2, description: '2 points per 2' });
const threes = new TotalOneNumber({ val: 3, description: '3 points per 3' });
const fours = new TotalOneNumber({ val: 4, description: '4 points per 4' });
const fives = new TotalOneNumber({ val: 5, description: '6 points per 5' });
const sixes = new TotalOneNumber({ val: 6, description: '6 points per 6' });

// three/four of kind score as sum of all dice
const threeOfKind = new SumDistro({
  count: 3,
  description: 'Sum all dice if 3 are the same'
});

const fourOfKind = new SumDistro({
  count: 4,
  description: 'Sum all dice if 4 are the same'
});

// full house scores as flat 25
const fullHouse = new FullHouse({
  score: 25,
  description: '25 points for full house'

});

// small/large straights score as 30/40
const smallStraight = new SmallStraight({
  score: 30,
  description: '30 points for small straight'
});

const largeStraight = new LargeStraight({
  score: 40,
  description: '40 points for large straight'
});

// yahtzee scores as 50
const yahtzee = new Yahtzee({
  score: 50,
  description: '30 points for yahtzee'

});

// for chance, can view as some of all dice, requiring at least 0 of a kind
const chance = new SumDistro({ count: 0, description: 'Sum of all dice' });

export {
  ones,
  twos,
  threes,
  fours,
  fives,
  sixes,
  threeOfKind,
  fourOfKind,
  fullHouse,
  smallStraight,
  largeStraight,
  yahtzee,
  chance
};

```

**This is my non working refactored code:**

```auto
    // put all properties in params on instance
    Object.assign(params);
 
    function sum(dice) {
        // sum of all dice
        return dice.reduce((prev, curr) => prev + curr);
      }
  
    
    function freq(dice) {
    // frequencies of dice values
       const freqs = new Map();
       for (let d of dice) freqs.set(d, (freqs.get(d) || 0) + 1);
       return Array.from(freqs.values());
      }
              
    
    function count(dice, val) {
    // # times val appears in dice
       
    return dice.filter(d => d === val).length;
      }

    
    /** Given a sought-for val, return sum of dice of that val.
     *
     * Used for rules like "sum of all ones"
     */
    
    const TotalOneNumber = {
        evalRoll: (dice, val) => {
        return val * count(dice, val);
        }
    }
  
  /** Given a required # of same dice, return sum of all dice.
   *
   * Used for rules like "sum of all dice when there is a 3-of-kind"
   */
  
    const sumDistro = {
    evalRoll: dice => {
      // do any of the counts meet of exceed this distro?
      return freq(dice).some(c => c >= count) ? sum(dice) : 0;
    }
  }
  
    /** Check if full house (3-of-kind and 2-of-kind) */
  
   const fullHouse = {
    evalRoll: (dice, score) => {
      const freqs = freq(dice);
      return freqs.includes(2) && freqs.includes(3) ? score : 0;
    }
  }
  
  /** Check for small straights. */
  
    const smallStraight = {
    evalRoll: (dice, score) => {
      const d = new Set(dice);
      // straight can be 234 + either 1 or 5
      if (
        (d.has(2) && d.has(3) && d.has(4) && d.has(5) && d.has(2)) ||
        d.has(5)
      ) {
        return score;
      }
  
      // or 345 + either 2 or 6
      if ((d.has(3) && d.has(4) && d.has(5) && d.has(2)) || d.has(6)) {
        return score;
      }
  
      return 0;
    }
  }
  
  /** Check for large straights. */
  
    const largeStraight = {
    evalRoll: (dice, score) => {
      const d = new Set(dice);
  
      // large straight must be 5 different dice & only one can be a 1 or a 6
      return d.size === 5 && (!d.has(1) || !d.has(6)) ? score : 0;
    }
  }
  
  /** Check if all dice are same. */
  
    const yahtzee = {
    evalRoll: (dice, score) => {
      // all dice must be the same
      return freq(dice)[0] === 5 ? score : 0;
    }
  }
  
    // ones, twos, etc score as sum of that value
    const ones = new TotalOneNumber({ val: 1, description: '1 point per 1' });
    const twos = new TotalOneNumber({ val: 2, description: '2 points per 2' });
    const threes = new TotalOneNumber({ val: 3, description: '3 points per 3' });
    const fours = new TotalOneNumber({ val: 4, description: '4 points per 4' });
    const fives = new TotalOneNumber({ val: 5, description: '6 points per 5' });
    const sixes = new TotalOneNumber({ val: 6, description: '6 points per 6' });
  
    // three/four of kind score as sum of all dice
    const threeOfKind = new sumDistro({
        count: 3,
        description: 'Sum all dice if 3 are the same'
    });
    const fourOfKind = new sumDistro({
        count: 4,
        description: 'Sum all dice if 4 are the same'
    });
    
    // full house scores as flat 25
    const FullHouse = new FullHouse({
        score: 25,
        description: '25 points for full house'
    });
    
    // small/large straights score as 30/40
    const SmallStraight = new SmallStraight({
        score: 30,
        description: '30 points for small straight'
    });
    const LargeStraight = new LargeStraight({
        score: 40,
        description: '40 points for large straight'
    });
    
    // yahtzee scores as 50
    const Yahtzee = new Yahtzee({
        score: 50,
        description: '30 points for yahtzee'
    });
    
    // for chance, can view as some of all dice, requiring at least 0 of a kind
    const chance = new sumDistro({ count: 0, description: 'Sum of all dice' });
    
   export {
        ones,
        twos,
        threes,
        fours,
        fives,
        sixes,
        threeOfKind,
        fourOfKind,
        fullHouse,
        smallStraight,
        largeStraight,
        yahtzee,
        chance,
    };

```

Unfortunately, I am struggling to make this work, can someone help me, what am I doing wrong here?

---

<div class="post-metadata">

**Author:** ![kirupa](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/kirupa/32/11616_2.png) [@kirupa](https://forum.kirupa.com/u/kirupa)\
**Post date:** [October 28, 2021, 5:50pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/2 "2021-10-28T17:50:48Z")

</div>

What is the error you are seeing in the console?

---

<div class="post-metadata">

**Author:** ![pepasteel](https://avatars.discourse-cdn.com/v4/letter/p/59ef9b/32.png) [@pepasteel](https://forum.kirupa.com/u/pepasteel)\
**Post date:** [October 28, 2021, 6:41pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/3 "2021-10-28T18:41:02Z")

</div>

You can see what this is all about here at this link: [Yahtzee - Codesandbox](https://codesandbox.io/embed/adoring-maxwell-dy5om?fontsize=14&hidenavigation=1&theme=dark)

I see this error in the console:

```auto
Uncaught TypeError: TotalOneNumber is not a constructor
    at Module.<anonymous> (Rules.js:100)
    at Module../src/components/Rules.js (Rules.js:328)
    at __webpack_require__ (bootstrap:851)
    at fn (bootstrap:150)
    at Module.<anonymous> (Rules.js:328)
    at Module../src/components/ScoreTable.js (ScoreTable.js:117)
    at __webpack_require__ (bootstrap:851)
    at fn (bootstrap:150)
    at Module.<anonymous> (Die.js:27)
    at Module../src/components/Game.js (Game.js:133)
    at __webpack_require__ (bootstrap:851)
    at fn (bootstrap:150)
    at Module.<anonymous> (App.css?dde5:82)
    at Module../src/App.js (App.js:14)
    at __webpack_require__ (bootstrap:851)
    at fn (bootstrap:150)
    at Module.<anonymous> (index.css?bb0a:82)
    at Module../src/index.js (index.js:10)
    at __webpack_require__ (bootstrap:851)
    at fn (bootstrap:150)
    at Object.1 (index.js:10)
    at __webpack_require__ (bootstrap:851)
    at checkDeferredModules (bootstrap:45)
    at Array.webpackJsonpCallback [as push] (bootstrap:32)
    at main.chunk.js:1
webpackHotDevClient.js:138 src\components\Game.js
  Line 37:6: React Hook useEffect has a missing dependency: 'animateRoll'. Either include it or remove the dependency array react-hooks/exhaustive-deps

src\components\Rules.js
  Line 118:23: 'FullHouse' was used before it was defined no-use-before-define
  Line 124:27: 'SmallStraight' was used before it was defined no-use-before-define
  Line 128:27: 'LargeStraight' was used before it was defined no-use-before-define
  Line 134:21: 'Yahtzee' was used before it was defined no-use-before-define

```

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/senocular/32/7217_2.png) [@senocular](https://forum.kirupa.com/u/senocular)\
**Post date:** [October 28, 2021, 10:47pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/4 "2021-10-28T22:47:06Z")

</div>

There are no react components in your code. These are all just normal JavaScript classes. You can’t convert them to react functional components.

---

<div class="post-metadata">

**Author:** ![pepasteel](https://avatars.discourse-cdn.com/v4/letter/p/59ef9b/32.png) [@pepasteel](https://forum.kirupa.com/u/pepasteel)\
**Post date:** [October 29, 2021, 1:01am UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/5 "2021-10-29T01:01:59Z")

</div>

I will reformulate the question since I did not express myself well. I want to rewrite the code from above using traditional function-based syntax. Something like this: [Sub classing with extends](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#sub_classing_with_extends)

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/senocular/32/7217_2.png) [@senocular](https://forum.kirupa.com/u/senocular)\
**Post date:** [October 29, 2021, 2:04am UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/6 "2021-10-29T02:04:03Z")

</div>

When you say “something like this” do you mean like that but not using classes (because that link uses classes)?

And are you trying to be functional or just not use classes? What exactly are you after in attempting this conversion?

---

<div class="post-metadata">

**Author:** ![pepasteel](https://avatars.discourse-cdn.com/v4/letter/p/59ef9b/32.png) [@pepasteel](https://forum.kirupa.com/u/pepasteel)\
**Post date:** [October 29, 2021, 9:26am UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/7 "2021-10-29T09:26:48Z")

</div>

I’m trying that Rules be functional not class.

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/senocular/32/7217_2.png) [@senocular](https://forum.kirupa.com/u/senocular)\
**Post date:** [October 29, 2021, 3:13pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/8 "2021-10-29T15:13:14Z")

</div>

If you’re trying to be functional then you want to think in terms of functions. You kind of started off that way (`function sum(dice)...`) but then you went into objects (`const TotalOneNumber = {`…) and then continued to try to `new` things which is going back to instantiating classes - classes which you should no longer have, and actually don’t, hence the errors.

The somewhat tricky part here is dealing with your parameter state, namely val, description, count, and score. count, by the way, is a bad parameter name because it conflicts with the count method. Luckily, this state never changes so it should be pretty straightforward to make function versions of these classes/methods since its all just inputs producing outputs with no side effects. What was state can now be just another input.

… actually it looks like steve.mills is replying so I’m going to see what happens there before I continue (I have some errands to run now anyway 🙃 )

---

<div class="post-metadata">

**Author:** ![steve.mills](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/steve.mills/32/14961_2.png) [@steve.mills](https://forum.kirupa.com/u/steve.mills)\
**Post date:** [October 29, 2021, 4:07pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/9 "2021-10-29T16:07:53Z")

</div>

I love FP and you can learn a lot from functional programming.  
Function composition, generic reusable functions, clean code, provable functions ect.

The basic premise of functional programming is:

- copy data without mutating
- pipe data through a series of single purpose pure functions by copying and not mutating
- don’t save store any actions as variables (not even an iteration)
- output the data as a response or to an interface using an “impure” IO function

This is great for back end data base type operations where performance is not critical but correctness is.

Even Rust a systems level language is immutable by default and supports higher order functions.

However for 95% of all front end JS, functional programming is unnecessary and bad for performance.

FP is great to learn and makes you a better programmer in 2 key areas:

- Clean code: Pure single purpose functions are nice
- Higher order functions: understanding passing functions as arguments, piping composition ect is really usefull

If you really want to learn Functional Programming in JS Brian Lonsdorf has a course on Front End Masters, Egghead IO and a book thats free. Be prepared to go down the rabbit hole. 😁

I personally wouldn’t try to change existing front end JS to an FP style unless you were trying to clean up really bad code and make it more readable.

Also:

- Loops are fine, you don’t need recursion (you can also write an immutable map function with a loop)
- Mapping repeatedly throughout a pipe or compose is a waste of memory
- You don’t need monads/ monoids. `Promise` is like a monad and `async functions/ await` is more performant and easier to read.

To be honest if you really want to get into FP…

- front end: Elm is great (its a compile to JS language and a framework).
- back end: Elixer is pretty kick ass but hard to learn (runs on Erlang)
- up and coming: Roc (from the creators /primary users of Elm, in development)

Just use whatever style of programming that is best suited to your project/ framework. Take the good parts of FP, OO ect and write easy to understand/ test and debug code.

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/senocular/32/7217_2.png) [@senocular](https://forum.kirupa.com/u/senocular)\
**Post date:** [October 29, 2021, 10:22pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/10 "2021-10-29T22:22:29Z")

</div>

Looking at the original, it seems the Rules class doesn’t do much more than save the params its given (via assign) and set up a few helper functions, none of which actually refer to those params. This is good because they can be easily ripped out and made into simple, standalone functions - something you’ve already done, so off to a good start.

After that there are some other classes that all extend Rules, but all of these only ever define a single `evalRoll` method. So really, these can effectively just _be_ that method as a function. You’re putting them in objects in your refactored code which isn’t necessary since they all simply wrap one function. Instead just make them the function. So

```javascript
class TotalOneNumber extends Rule {
  evalRoll = dice => {
    return this.val * this.count(dice, this.val);
  };
}

```

would loosely become

```javascript
function totalOneNumber(dice) {
  return this.val * this.count(dice, this.val);
}

```

The problem now is getting rid of `this`. `this` would represent the current instance and the members within that instance but we’re not dealing with classes an instances anymore, just functions with simple inputs and outputs.

There’s two uses of `this`, one for `val` and one for `count`. `count` is easy, that’s a function we ripped out earlier so that can just drop the `this` and simply work. `val` is something that would be coming from the params passed into the constructor during instantiation of the class. Its another kind of input, one that would be coming from the instance rather than the arguments, but we can simply move it to be an argument input instead because we no longer have an instance. That gives us

```javascript
function totalOneNumber(val, dice) {
  return val * count(dice, val);
}

```

You can then repeat this process for the other classes as well.

After the classes, we set the individual numbers being instantiated from the TotalOneNumber class. Each of these instances contain the functionality of the TotalOneNumber class but each having a different `val` property (there’s a description too, but we can ignore that for now since I don’t know how it’s being used).

Since the refactor doesn’t have instances, these would instead have to be represented as functions… or do they? Wouldn’t each of these instead just calling the new `totalOneNumber(val, dice)` function with a different `val` argument each time? Well, yes, but we can also make new function versions of `totalOneNumber(val, dice)` with those values baked in using partial application. JavaScript can do this with the native `bind()` method. That would look something like this:

```javascript
const ones = totalOneNumber.bind(null, 1);
const twos = totalOneNumber.bind(null, 2);
const threes = totalOneNumber.bind(null, 3);
const fours = totalOneNumber.bind(null, 4);
const fives = totalOneNumber.bind(null, 5);
const sixes = totalOneNumber.bind(null, 6);

```

Now, each of these are new functions which calls `totalOneNumber(val, dice)` with the `val` pre-defined. `ones`, for example, would have the signature of `ones(dice)` and would use `1` as the value of `val` in its function body which is that of `totalOneNumber`, or more specifically something like:

```javascript
function ones(dice) {
  return 1 * count(dice, 1);
}

```

Lets test it out (full script with all necessary dependencies so you can copy and paste and run somewhere):

```javascript
function count(dice, val) {
  return dice.filter(d => d === val).length;
}

function totalOneNumber(val, dice) {
    return val * count(dice, val);
}

const ones = totalOneNumber.bind(null, 1);
const twos = totalOneNumber.bind(null, 2);
const threes = totalOneNumber.bind(null, 3);

const dice = [1,1,2,2,3];
console.log('ones:', ones(dice)); // 2 (1x2)
console.log('twos:', twos(dice)); // 4 (2x2)
console.log('threes:', threes(dice)); // 3 (3x1)

```

The other classes aren’t very different and would need a similar treatment. You think you could do the rest yourself? Just be sure to not confuse the `count` parameter and the `count` function. When you’re done there should be no references to `this` or `new`. What you’ll be exporting will be a list of functions, not a list of object instances, and these functions would be used in place of `instance.evalRoll()` (e.g. what was `ones.evalRoll(dice)` would instead become `ones(dice)`).

---

<div class="post-metadata">

**Author:** ![steve.mills](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/steve.mills/32/14961_2.png) [@steve.mills](https://forum.kirupa.com/u/steve.mills)\
**Post date:** [October 31, 2021, 8:28am UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/12 "2021-10-31T08:28:35Z")

</div>

Been having a play with it and did up a function that returns a score from a five number array.

Loops are more efficient than `Map` because they don’t create a function object every iteration.  
You can also `return` the main function and `break` from a loop.

It tally’s the array for each number on the dice 0-6 into a frequency array (disregard 0).  
Then loops and checks for Full House (2 + 3 of a kind), 3/4/5 of a kind.  
If that doesn’t return it checks for Low and High Straight .  
Failing that returns 0;

```auto
const check = function(arr){
  // efficient reduce function
  let count = function(ar){ let acc = 0; for(let i of ar){acc += i} return acc }
  
  let two = null, thr = null, frq = [0,0,0,0,0,0,0];  
  // sets the frequency of roll numbers to frq array
  for(let i of arr){frq[i] ++}
  
  for(let i of frq){
    // 2 and 3 of a kind  
    i == 2 ? two = 1 : i == 3 ? thr = 1 : 0;
    // Four of a kind
    if(i == 4) return count(arr)
    //yahtzee
    if(i == 5) return 50;
  }
  // Full house
  if(two && thr) return 25
  // Three of a kind // wait to check for full house
  if(thr) return count(arr)
  
  let cnt = 0, low = 0, val = NaN;
  for(let x of arr) {
    // checks for Low straight before setting count to 0
    cnt == 3 ? low = 1 : 0;
    // counts each sequential incremental number
    val == (x -1) ? cnt ++ : cnt = 0;
    //set val to current iteration for next loop to compare
    val = x;
  }
    // High straight
    if(cnt == 4) return 40; 
    // Low Straight
    if(low == 1 || cnt == 3) return 30;
    return 0;
}

```

```auto
// Nothing Roll
console.log(check([1,3,1,2,5])) // returns 0

// Full House
console.log(check([1,1,1,2,2])) // returns 25

// 3 of a kind
console.log(check([1,6,1,2,1])) // returns 11

// Four of a kind
console.log(check([5,5,5,5,1])) // returns 21

// Low straight
console.log(check([1,2,3,4,6])) // returns 30

// High straight
console.log(check([2,3,4,5,6])) // returns 40

// Yahtzee
console.log(check([6,6,6,6,6])) // returns 50

```

without comments

```auto
const check = function(arr){
  let count = function(ar){ let acc = 0; for(let i of ar){acc += i} return acc }
  let two = null, thr = null, frq = [0,0,0,0,0,0,0];  
  for(let i of arr){frq[i] ++}
  
  for(let i of frq){ 
    i == 2 ? two = 1 : i == 3 ? thr = 1 : 0;
    if(i == 4) return count(arr)
    if(i == 5) return 50;
  }
  if(two && thr) return 25
  if(thr) return count(arr)
  
  let cnt = 0, low = 0, val = NaN;
  for(let x of arr) {
    cnt == 3 ? low = 1 : 0;
    val == (x -1) ? cnt ++ : cnt = 0;
    val = x;
  }
    if(cnt == 4) return 40; 
    if(low == 1 || cnt == 3) return 30;
    else return 0;
}

```

---

<div class="post-metadata">

**Author:** ![pepasteel](https://avatars.discourse-cdn.com/v4/letter/p/59ef9b/32.png) [@pepasteel](https://forum.kirupa.com/u/pepasteel)\
**Post date:** [November 5, 2021, 4:43pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/13 "2021-11-05T16:43:23Z")

</div>

@ [senocular](http://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/10) I don’t know how to thank you for such an exhaustive and good explanation. I did a refactoring according to your suggestions and the part related to results from one to six is working properly.  
This is how the code looks like now:

> /\*\* Functions for summing, counting values, and counting frequencies of dice.  
> \*/
> 
> function sum(dice) {  
> // sum of all dice  
> return dice.reduce((prev, curr) =\> prev + curr);  
> }
> 
> function freq(dice) {  
> // frequencies of dice values  
> const freqs = new Map();  
> for (let d of dice) freqs.set(d, (freqs.get(d) || 0) + 1);  
> return Array.from(freqs.values());  
> }
> 
> function count(dice, val) {  
> // # times val appears in dice  
> return dice.filter(d =\> d === val).length;  
> }
> 
> /\*\* Given a sought-for val, return sum of dice of that val.  
> Used for rules like “sum of all ones”  
> \*/
> 
> function totalOneNumber(val, dice) {  
> return val \* count(dice, val);  
> }
> 
> /\*\* Given a required # of same dice, return sum of all dice.  
> Used for rules like “sum of all dice when there is a 3-of-kind”  
> \*/
> 
> function sumDistro(dice) {  
> // do any of the counts meet of exceed this distro?  
> return freq(dice).some(c =\> c \>= count) ? sum(dice) : 0;  
> }
> 
> /\*\* Check if full house (3-of-kind and 2-of-kind) \*/
> 
> function fullHouseFn(dice, score) {  
> const freqs = freq(dice);  
> return freqs.includes(2) && freqs.includes(3) ? score : 0;  
> }
> 
> /\*\* Check for small straights. \*/
> 
> function smallStraightFn(dice, score) {  
> const d = new Set(dice);  
> // straight can be 234 + either 1 or 5  
> if (  
> (d.has(2) && d.has(3) && d.has(4) && d.has(5) && d.has(2)) ||  
> d.has(5)  
> ) {  
> return score;  
> }  
> // or 345 + either 2 or 6  
> if ((d.has(3) && d.has(4) && d.has(5) && d.has(2)) || d.has(6)) {  
> return score;  
> }  
> return 0;  
> }
> 
> /\*\* Check for large straights. \*/
> 
> function largeStraightFn(dice, score) {  
> const d = new Set(dice);
> 
> // large straight must be 5 different dice & only one can be a 1 or a 6  
> return d.size === 5 && (!d.has(1) || !d.has(6)) ? score : 0;  
> }
> 
> /\*\* Check if all dice are same. \*/
> 
> function yahtzeeFn(dice, score) {  
> // all dice must be the same  
> return freq(dice)[0] === 5 ? score : 0;  
> }
> 
> // ones, twos, etc score as sum of that value
> 
> const ones = totalOneNumber.bind(null, 1);  
> const twos = totalOneNumber.bind(null, 2);  
> const threes = totalOneNumber.bind(null, 3);  
> const fours = totalOneNumber.bind(null, 4);  
> const fives = totalOneNumber.bind(null, 5);  
> const sixes = totalOneNumber.bind(null, 6)
> 
> // three/four of kind score as sum of all dice  
> const threeOfKind = sumDistro({  
> count: 3,  
> description: ‘Sum all dice if 3 are the same’  
> });
> 
> const fourOfKind = sumDistro({  
> count: 4,  
> description: ‘Sum all dice if 4 are the same’  
> });
> 
> // full house scores as flat 25  
> const fullHouse = fullHouseFn({  
> score: 25,  
> description: ‘25 points for full house’  
> });
> 
> // small/large straights score as 30/40  
> const smallStraight = smallStraightFn({  
> score: 30,  
> description: ‘30 points for small straight’  
> });
> 
> const largeStraight = largeStraightFn({  
> score: 40,  
> description: ‘40 points for large straight’  
> });
> 
> // yahtzee scores as 50  
> const yahtzee = yahtzeeFn({  
> score: 50,  
> description: ‘30 points for yahtzee’  
> });
> 
> // for chance, can view as some of all dice, requiring at least 0 of a kind  
> const chance = sumDistro({ count: 0, description: ‘Sum of all dice’ });
> 
> export {  
> ones,  
> twos,  
> threes,  
> fours,  
> fives,  
> sixes,  
> threeOfKind,  
> fourOfKind,  
> fullHouse,  
> smallStraight,  
> largeStraight,  
> yahtzee,  
> chance,  
> };

Now, I have a problem with functions for threeOfKind, fourOfKind, fullHouse, etc …  
I got an error that occurs in the function freq.  
This is the error in the console:

> Uncaught TypeError: dice is not iterable!  
> at freq (Rules1.js:14)  
> at sumDistro (Rules1.js:45)  
> at Module. (Rules1.js:114)  
> at Module…/src/components/Rules1.js (Rules1.js:158)  
> at **webpack\_require** (bootstrap:851)  
> at fn (bootstrap:150)  
> at Module. (Rules1.js:158)  
> at Module…/src/components/ScoreTable.js (ScoreTable.js:285)  
> at **webpack\_require** (bootstrap:851)  
> at fn (bootstrap:150)  
> at Module. (Die.js:27)  
> at Module…/src/components/Game.js (Game.js:226)  
> at **webpack\_require** (bootstrap:851)  
> at fn (bootstrap:150)  
> at Module. (App.css?dde5:82)  
> at Module…/src/App.js (App.js:14)  
> at **webpack\_require** (bootstrap:851)  
> at fn (bootstrap:150)  
> at Module. (index.css?bb0a:82)  
> at Module…/src/index.js (index.js:10)  
> at **webpack\_require** (bootstrap:851)  
> at fn (bootstrap:150)  
> at Object.1 (index.js:10)  
> at **webpack\_require** (bootstrap:851)  
> at checkDeferredModules (bootstrap:45)  
> at Array.webpackJsonpCallback [as push] (bootstrap:32)  
> at main.chunk.js:1

 ![Screenshot 2021-11-05 at 17.38.34](https://canada1.discourse-cdn.com/flex011/uploads/kirupa/original/2X/6/61e3cd25eedd0261bb95423837bcbacec45f0010.png)

---

<div class="post-metadata">

**Author:** ![steve.mills](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/steve.mills/32/14961_2.png) [@steve.mills](https://forum.kirupa.com/u/steve.mills)\
**Post date:** [November 6, 2021, 7:01am UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/14 "2021-11-06T07:01:04Z")

</div>

I personally find Object Orientated programming is confusing and mostly unnecessary much like about half of Functional programming (algebraic notation, point free, natural tx ect).

I tend to use a mix of procedural and basic functional programming however, I do like classes for UI components/ CSS (custom elements).

An interesting take on class inheritance:  
[Object-Oriented Programming is Bad - YouTube](https://www.youtube.com/watch?v=QM1iUe6IofM&t=1427s)

_The problem appears to be these constants e.g_

```auto
const smallStraight = smallStraightFn({
score: 30,
description: ‘30 points for small straight’
});

```

_are calling these functions e.g._

```auto
function smallStraightFn(dice, score) {
const d = new Set(dice);
// straight can be 234 + either 1 or 5
if (
(d.has(2) && d.has(3) && d.has(4) && d.has(5) && d.has(2)) ||
d.has(5)
) {
return score;
}
// or 345 + either 2 or 6
if ((d.has(3) && d.has(4) && d.has(5) && d.has(2)) || d.has(6)) {
return score;
}
return 0;
}

```

_with the wrong arguments._

`smallStraightFn(dice, score)` expects an array as the first argument e.g. `[1,2,3,4,1]` and a score as the second argument e.g. `30`  
so `smallStraightFn([1,2,3,4,1], 25)` should `return 30`

BUT it’s being called with an object `smallStraightFn({score : 30})`

There is another problem:

In theory the function`smallStraightFn()` should return the constant `const smallStraight = { score: 30, description: ‘30 points for small straight’}`

After you call `smallStraightFn()` with an array `[1,2,3,4,1]` so the function verifies that the array is a “small straight”…

---

<div class="post-metadata">

**Author:** ![steve.mills](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/steve.mills/32/14961_2.png) [@steve.mills](https://forum.kirupa.com/u/steve.mills)\
**Post date:** [November 6, 2021, 10:17am UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/15 "2021-11-06T10:17:18Z")

</div>

Assuming an input an `array` of five (dice numbers) and output an object with the frequencies, total and description e.g

```auto
{ sixes: 5,
  score: '50',
  description: '50 points for Yahtzee'
}

```

The following block does this:

```auto
// more efficient freq function
const freq = function(arr){
  let frq = [0,0,0,0,0,0,0]
  for(let i of arr){frq[i] ++}
  return frq
}
// more efficient sum function
const sum = function(arr){
  let acc = 0; 
  for(let i of arr){acc += i} 
  return acc 
}
// replaces all those const = function()
const score = function({score, type}){
  return { score: `${score}`, description: `${score} points for ${type}`}
}

// checks for X of a kind incl Yahtzee and Full House
const checkKind = (frq,arr) => {
  let two = null, thr = null; 
  for(let i of frq){ 
    if(i == 2) two = 1;
    if (i == 3) thr = 1;
    if(i == 4) return {score: sum(arr), type: 'Four of a Kind'}
    if(i == 5) return {score: 50, type: 'Yahtzee'}
  }
  if(two && thr) return {score: 25, type: 'Full House'}
  if(thr) return {score: sum(arr), type: 'Three of a Kind'}
  else return 0;
}

// checks for Low / High Straight
const checkStraight = arr => {
  let count = 0, low = 0, val = NaN;
  for(let x of arr) {
    if(val == (x -1)) count ++;
    else { if(count == 3) low = 1; count = 0;}
    val = x;
  }
    if(count == 4) return {score: 40, type: 'Hight Straight'} 
    if(low == 1 || count == 3) return {score: 30, type: 'Low Straight'}
    return {score: 0, type: 'No Dice'}
}
// replaces all the bind functions
const frqObj = function([zero, ones, twos, threes, fours, fives, sixes]){ 
  let obj = {}
  if(ones !== 0) obj.ones = ones;
  if(twos !== 0) obj.twos = twos;
  if(threes !== 0) obj.threes = threes;
  if(fours !== 0) obj.fours = fours;
  if(fives !== 0) obj.fives = fives;
  if(sixes !==0) obj.sixes = sixes;
  return obj;  
}
// runs all the functions and returns a merged freq and score object
const check = function(arr){
  let frq = freq(arr);
  let vals = frqObj(frq);
  let kind = checkKind(frq, arr);
  let straight;
  let total;
  if(kind == 0){
    straight = checkStraight(arr);
    total = score(straight);
    return {...vals, ...total}
  }
  else {total = score(kind);
       return {...vals, ...total}
       }
}

// Nothing Roll
console.log(check([1,3,1,3,5])) 
// returns { ones: 2, threes: 2, fives: 1, score: '0',description: '0 points for No Dice'}

// Full House
console.log(check([1,1,1,2,2])) 
// returns { ones: 3, twos: 2, score: '25', description: '25 points for Full House'}

// 3 of a kind
console.log(check([1,6,1,2,1])) 

// Four of a kind
console.log(check([5,5,5,5,1])) 

// Low straight
console.log(check([1,2,3,4,6])) 

// High straight
console.log(check([2,3,4,5,6])) 

// Yahtzee
console.log(check([6,6,6,6,6]))

```

Have a play, see if you can work out what all the functions do in detail 🙂

---

<div class="post-metadata">

**Author:** ![louyi](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/louyi/32/16112_2.png) [@louyi](https://forum.kirupa.com/u/louyi)\
**Post date:** [November 30, 2021, 7:41pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/17 "2021-11-30T19:41:16Z")

</div>

did you finish the whole thing? Can i have a look? i’m trying to do the same with some other projects but i keep getting errors until i stumbled upon this, it may help me. 😄

---

<div class="post-metadata">

**Author:** ![kirupa](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/kirupa/32/11616_2.png) [@kirupa](https://forum.kirupa.com/u/kirupa)\
**Post date:** [November 30, 2021, 11:04pm UTC](https://forum.kirupa.com/t/refactoring-class-component-to-react-functional-component/649442/18 "2021-11-30T23:04:17Z")

</div>

Hi @louyi - welcome to the forums 🙂

If you have a smaller code repro where you are having difficulties, it may not be a bad idea to create a new topic dedicated just to your question.
