Holden1515
Holden1515

Reputation: 699

Looping through a Map in React

I have a Map object:

let dateJobMap = new Map();

for (let jobInArray of this.state.jobs) {
  let deliveryDate: Date = new Date(jobInArray.DeliveryDate);
  let deliveryDateString: string = deliveryDate.toLocaleDateString("en-US");

  if (dateJobMap.has(deliveryDateString)) {
    let jobsForDate: IDeliveryJob[] = dateJobMap.get(deliveryDateString);
    jobsForDate.push(jobInArray);
  }
  else {
    let jobsForDate: IDeliveryJob[] = [jobInArray];
    dateJobMap.set(deliveryDateString, jobsForDate);
  }
}

In my render method, I want to call a TruckJobComp object for each delivery job in the value's array to display it:

        <div className={ styles.column }>
          <p className={ styles.description }>{escape(this.props.description)}</p>

          {
            dateJobMap.forEach(function(jobsForDate, dateString) {
              jobsForDate.map(job => (
                <TruckJobComp job = { job } />
              ))
            })
          }
        </div>

This seems like it should work but doesn't. It never creates a TruckJobComp. I do a .forEach iteration on my Map, and for each value's array, I use .map to get the individual job object to send to TruckJobComp object.

When I create a temp array to grab the jobs from the last loop:

let tempJobs: IDeliveryJob[];

and in the loop add in:

  if (dateJobMap.has(deliveryDateString)) {
    let jobsForDate: IDeliveryJob[] = dateJobMap.get(deliveryDateString);
    jobsForDate.push(jobInArray);

    tempJobs = jobsForDate;
  }

and then use that array in the render:

          <div className={ styles.column }>
            <p className={ styles.description }>{escape(this.props.description)}</p>
            {
              tempJobs.map(job => (
                <TruckJobComp job = { job }/>
              ))
            }
          </div>

It displays as expected.

I do have a warnings in Visual Studio Code:

Warning - tslint - ...\TruckDeliverySchedule.tsx(104,38): error no-function-expression: Use arrow function instead of function expression

I don't know enough to understand. Line 104 corresponds with:

dateJobMap.forEach(function(jobsForDate, dateString) {

I am very new to this so I'm not 100% sure how most of this works. Just trying to put pieces I've learned together to get things to work.

Second Edit:

{escape(this.props.description)}

{
  [...dateJobMap.keys()].map(jobsForDate => // line 154
    jobsForDate.map(job => (
      <TruckJobComp job = { job } />
    ))
  )
}

Produces error:

[09:06:56] Error - typescript - src\...\TruckDeliverySchedule.tsx(154,27): error TS2461: Type 'IterableIterator<any>' is not an array type.

Upvotes: 25

Views: 64430

Answers (4)

Lasitha Lakmal
Lasitha Lakmal

Reputation: 880

If you want to iterate the value set using Typescript, rather than iterating the key set use this method. But don't forget to update the target es version in the tsconfig.json file under compilerOptions

[...p.delData_c.entries()].map(([key, value]) =>
     <PickedIItemPack group={value} />
)

in tsconfig.json add this line

"target": "es2015"

under compilerOptions scope

Upvotes: 0

Sandeep Jain
Sandeep Jain

Reputation: 1262

To iterate over a Map, we can use for..of and forEach() loop constructs. Map provides three methods that return iterable: map.keys(), map.values() and map.entries().

Iteration over Maps is always in insertion order.

                    let map = new Map()
                    
                    map.set("one", "first element");
                    map.set("two", "second element");
                    map.set(3, "third element");    
                    
                         for (let [key, value] of map) {
                                console.log(key+" : "+value);
                                }
                
                map.keys() - Returns an iterable for keys
                map.values() - Returns an iterable for values
                map.entries() - Returns an iterable of key,value
            
            Example
            
            for (let key of map.keys()) {
                console.log(key);
            }
            
            // output
            // one
            // two
            // 3
            
            for (let value of map.values()){
                console.log(value);
            }
            
            // output
            // first element
            // second element
            // third element
            
            for (let [key, value] of  map.entries()) {
                console.log(key + " = " + value)
            }
            
            //output
            // one = first element
            // two = second element
            // 3 = third element
        
        map.forEach(function(value, key) {
            console.log(key + " = " + value);
        })
        
        //output
        // one = first element
        // two = second element
        // 3 = third element

Upvotes: 0

Estus Flask
Estus Flask

Reputation: 222369

dateJobMap.forEach(...) returns undefined, so it cannot be mapped to a collection of elements.

ES6 maps have forEach method for compatibility purposes (generally for..of is preferred to iterate over iterables) and don't have map method. A map should be converted to array first, then it could be mapped to an element. Since values aren't used, only keys need to be retrieved:

  {
    [...dateJobMap.keys()].map(jobsForDate =>
      jobsForDate.map(job => (
        <TruckJobComp job = { job } />
      ))
    )
  }

Upvotes: 36

jaredkwright
jaredkwright

Reputation: 1380

All this warning is saying is that instead of using the syntax function(jobsForDate, dateString) {} you should use the syntax (jobsForDate, dateString) => {}.

The reason could be the way this is scoped in arrow functions versus function expressions. See this post.

My guess as to the reason your first approach didn't work but your second one did is that forEach doesn't actually return an array, and if it did, calling map within forEach would return an array of arrays (but, again, it doesn't). Not sure how React would handle that, but React does know how to handle a single array, which is what your last approach returns.

Upvotes: 2

Related Questions