0

I have no problem setting flat object immutable records. But now I have a problem where I would like to setup a record, I guess maybe a list of records? I'm trying to get my User ref in my firebase database into a immutable record, or records.

So I load my users ref from firebase. It's structure looks like.

enter image description here

I can't figure out how to nest with lists. User has a list of UID's. From there it gets much flatter. But is this even possible to have a List of Records? I haven't seen any examples online so I'm just lost at this point. Any help would be great appreciated.

If I was doing something flatter like just profile it would look like.

  export const Profile = Record({
    key: null,
    profileName: '',
    profilePic: '',
    teamName: '', 
  });

It seems getting past the list of UID's is the first challenge Im having a hard time getting past. Once past that initial list it is much flatter.

Maybe I shouldn't even be doing this immutable. Im open to other suggesting for what to do with this data. Im just used to using Immutable records in my application at this point. Was hoping to stick to that pattern for this last bit I have.

Puerto
  • 1,072
  • 3
  • 11
  • 32
  • I am having trouble understanding your question?What do you mean nest with lists? – Shyam Babu Nov 06 '18 at 09:56
  • @ShyamBabu. Im having trouble trying to understand how I can use immutable for a list of objects that have some nesting inside each item in the list essentially. that is the question. How do Ideal with the list of users and have the nested record for each users profile in the list. Is that even possible?? – Puerto Nov 06 '18 at 16:07
  • https://stackoverflow.com/questions/29589753/how-to-update-element-inside-list-with-immutablejs/29655323 similar to this? – Shyam Babu Nov 06 '18 at 17:22
  • @ShyamBabu . Thanks for the response. That post looks more like updating. I want to create records. This GitHub issue sort of touches on what I want, but I haven't be able to figure it out to resolve my case where I have first have a list of UserId which then have records for each item containing profile data for the user. That essentially the structure I'm I would like but again I'm not even sure it's possible. Can you have a list with records nested for each item in the list? https://github.com/facebook/immutable-js/issues/385 – Puerto Nov 06 '18 at 17:44

2 Answers2

2

Basically there is no list of records as of yet. From what I could find you could use map with record values and extend Record class as per this answer to get equivalent to what you want(the code below is based on this approach).

I also could find an interesting article that had multiple approaches, for the same idea in a functional wayhere.

If this is not exactly what you were expecting let me know.

var users = {
   'efbluh': {
    'profile': {
      profileName: 'bill',
      profilePic: 'https://blue',
      teamName: 'locals', 
    },
    'team': {
        'Lpphasd' : {
            competitorKey: 'a'
        }
    }
   },
   'fixbluh': {
    'profile': {
      profileName: 'bill',
      profilePic: 'https://blue',
      teamName: 'locals', 
    },
    'team': {
        'Lpphasd' : {
            competitorKey: 'a'
        },
        'asdsadasda' : {
            competitorKey: 'b'
        }
    }
   }
  };

var ProfileRecord = Immutable.Record({
    profileName: '',
    profilePic: '',
    teamName: '', 
  });
var teamRecord = Immutable.Record({
       competitorKey: ''
 });

class User extends Immutable.Record({'profile': new ProfileRecord(), 'team':Immutable.Map()}) {
  constructor({profile, team} = {}) {
    super({team: Immutable.Map(team).map(x=>new teamRecord(x)), profile: new ProfileRecord(profile)})
  }
}

var userMap = Immutable.Map(users).map(x=>new User(x));

// Verify that it's really a record
console.log(userMap.get('efbluh').get('profile').profileName)
console.log(userMap.get('fixbluh').toJS())
console.log(userMap.get('fixbluh').get('team').toJS())
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.7.4/immutable.min.js"></script>
Shyam Babu
  • 1,069
  • 7
  • 14
  • Thank your for this suggestion. I've already upvoted as this looks promising. It will take me some time to flush through this. I might not get to it until friday, it's a home project I have and im doing day job stuff for next 2 days. But I will definitely post back here and let you know the results It looks very interesting. I would have never come up with this idea. Appreciate it. – Puerto Nov 07 '18 at 15:53
  • 1
    I can understand. Good luck. :) – Shyam Babu Nov 07 '18 at 17:34
  • So there's definitely something to this. It took me some time adapting this to work within my React/Redux app. Im using a selector as well to do the finishing moves on the 'users' data chunk. Im not totally through it all but I think I'll have something soon. Will post it when done but you have opened my eyes to something here. I think I'm going to get something out of this that will work. Update with final solution soon. – Puerto Nov 09 '18 at 23:17
  • I got it. I'm going to post how I wired it into redux and with selectors but I accepted your answer. It really worked well. I would have never gotten that on my own. Thank you @ShyamBabu – Puerto Nov 10 '18 at 14:08
0

Shyams suggestion was absolutely on point so it's the accepted answer. Most people should be able to adopt that if you have a need. However if you are like me, and are using firebase with redux and selectors here is how Shyams suggestion worked for me. Im not claiming it to be the most pure example of react/redux/selectors you've ever seen but it's working for me.

Without further ado.

Initially I get my Users from a redux action and reducer.

My action and action creators to fetch the data from firebase and initially store it in a Key Value Immutable Record from some high level firebase db functions I have.

import * as types from './actionTypes';
import { Record } from 'immutable';
import { FirebaseList } from 'src/firebase';

export const League = new Record({
  key: null,
  value: null
})

export const leagueFireDB = new FirebaseList({
  onLoad: loadLeagueSuccess,
},League);

export function loadLeague() {
  console.log("LOADLEAGUE::");
  return dispatch => {
    leagueFireDB.path = `users/`;
    leagueFireDB.subscribeChild(dispatch);
  };
}


export function loadLeagueSuccess(league) {
  console.log("LEAGUElOADSuccess::", league);
  return {
    type: types.LOAD_LEAGUE_SUCCESS,
    payload: league
  };
}

In the reducer, to get a proper return of all the deeply nested data to my connected component I used fromJS. Maybe there's a better way to do this but this worked for me.

import { Record, fromJS } from 'immutable';
import {
    LOAD_LEAGUE_SUCCESS,
    LOAD_LEAGUE_ERROR,
} from '../actions/actionTypes';

export const LeagueState = new Record({
    key: null,
    value: null
})

export function leagueReducer(state = new LeagueState(), {payload, type}) {
    switch (type) {
        case LOAD_LEAGUE_SUCCESS:
        return state.merge(fromJS(payload));
        
        default:
            return state;
    }

}

In my league page, a connected component, I have a selector wired in my mapstate to props

const mapStateToProps = (state, ownProps) => {
    console.log("MYSTATE::",state)
    return {
        league: LeagueSelector(state),
    }
  }

Then in my selector is where I do the finishing move on Users data by nesting the records and maps specified in the accepted answer.

import { createSelector } from 'reselect';
import { Record, Map } from 'immutable';

var ProfileRecord = Record({
  profileName: '',
  profilePic: '',
  teamName: '', 
});

var teamRecord = Record({
     competitorKey: ''
});

class User extends Record({'profile': new ProfileRecord(), 'team':Map()}) {
  constructor({profile, team} = {}) {
    super({team: Map(team).map(x=>new teamRecord(x)), profile: new ProfileRecord(profile)})
  }
}

export function getLeague(state) {
  return state
}

export function getLeagueList(state) {
  return Map(state.league.value).map(x=>new User(x));
}

//=====================================
//  MEMOIZED SELECTORS
//-------------------------------------

export const LeagueSelector = createSelector(
    getLeague,
    getLeagueList,
);

And here is the final proof of our neatly deeply nested immutable chaos. :)

enter image description here

Puerto
  • 1,072
  • 3
  • 11
  • 32