Reduce Method and From method - confusion

Hi there,

I am following a react course (CS50M) https://github.com/SilvercutYaz/cs50M

I am having problem understanding some JS code:

  1. What is the addkeys doing? it takes in a val and key and then returns the key? and a spread operator? im not entirely sure what’s happening here. (Contacts.js)

// add keys to based on index
const addKeys = (val, key) => ({key, ...val})

// create an array of length NUM_CONTACTS and add keys
export default Array.from({length: NUM_CONTACTS}, createContact).map(addKeys)
  1. there is an reduce and from method below that i dont really understand ( SectionListContacts.js
const SectionListContacts = props => {
  const contactsByLetter = props.contacts.reduce((obj, contact) => {
    const firstLetter = contact.name[0].toUpperCase()
    return {
      ...obj,
      [firstLetter]: [...(obj[firstLetter] || []), contact],
    }
  }, {})

  const sections = Object.keys(contactsByLetter).sort().map(letter => ({
    data: contactsByLetter[letter],
    title: letter,
  }))

i would appreciate your help if i could understand this. thanks

It is being used as the map method’s callback function, so val is each element and key is the index of corresponding element.

The addKeys function returns an object with a key property and also adds all the properties of val (which is an object containing a name and phone property) via the spread operator.

By using the spread operator instead of specifying the name and phone number properties, it allows the possibility of later changing the createContact function to maybe add an additional dynamically created property without also having to change the addKeys function.

What specifically do you not understand about the reduce method being used in SectionListContacts?

fantastic explanation for addkeys thanks. why must val be the first argument that is passed in? 3) i changed the arguments around and it produces a different result. So i am not 100% sure why that is.

// add keys to based on index
const addKeys = (val, key) => ({key:key, ...val})

// create an array of length NUM_CONTACTS and add keys
const generate = () => Array.from({length: NUM_CONTACTS}, createContact)

0: {name: "Lincoln Davies", phone: "825-442-5845"}
1: {name: "Andrew Mitchell", phone: "881-424-6703"}
// add keys to based on index
const addKeys = (val, key) => ({key:key, ...val})

// create an array of length NUM_CONTACTS and add keys
const generate = () => Array.from({length: NUM_CONTACTS}, createContact).map(addKeys)

0: {key: 0, name: "Scarlett King", phone: "309-869-1290"}
1: {key: 1, name: "Scarlett Scott", phone: "843-747-7404"}
// add keys to based on index
const addKeys = (key, val) => ({key:key, ...val})

// create an array of length NUM_CONTACTS and add keys
const generate = () => Array.from({length: NUM_CONTACTS}, createContact).map(addKeys)

0:
key: {name: "Stella Murphy", phone: "603-639-3162"}
__proto__: Object
1:
key: {name: "Alexander Young", phone: "818-135-7262"}
__proto__: Object

Also just confirming the spread operator below for future reference. Indeed the same:

It is not the val must be the first argument. The arguments can be named anything you want. What you must understand is the callback function for map dictates what the values of the arguments in the callback are. I suggest working through Free Code Camp’s map challenge to gain a better understanding of how to use it.

1 Like

May i explain what i think is happening and see if i’m wrong?

  1. obj is a list/section that displays on the screen (not the full contacts array; technically obj will display the section of arrays only) with key value pairs

  2. contact is one contact with key value pairs

  3. the reduce function firstly:
    a) sets a function that capitalises the first letter of the string of “name”
    b) returns a new object with i) the old object key value pairs and ii) appends a new key value pair such that name: Amanda should return key A: value [all objects cloned but with contact.name uppercased]

iii) i think the “contact” refers to the object that is being mutated? i.e., […obj[firstletter]] is applied to contact. yes?

Your response is hugely appreciated.

const SectionListContacts = props => {
  const contactsByLetter = props.contacts.reduce((obj, contact) => {
    const firstLetter = contact.name[0].toUpperCase()
    return {
      ...obj,
      [firstLetter]: [...(obj[firstLetter] || []), contact],
    }
  }, {})

I will look at the challenge. thanks :slight_smile:

array .map( function(currentValue, index, arr), thisValue )

currentValue Required. The value of the current element
index Optional. The array index of the current element