Reactotron: Typescript Map value is not displayed in State

Created on 23 Jul 2018  路  9Comments  路  Source: infinitered/reactotron

Hi 馃憢,

I'm using Reactotron with a React-Native project.
Everything works like a charm except for one of my store properties that's a TS Map.
The value in the State tab is not showing at all, even though I can debug it and see its value properly.

image

Here's my questionnaire state:

export default interface IQuestionnaireState {
  loading: boolean;
  errorMessage: string | null;
  questions: IOnboardingQuestion[];
  savingAnswer: boolean;
  saveAnswerErrorMessage: string | null;
  // Map<question id, answer id>
  selectedAnswers: Map<string, string>;
}

Not sure if this is a TS issue or Reactotron one...
Feel free to close if not relevant at all...

bug help wanted

Most helpful comment

Ya something is off here for sure. The way we serialize doesn't seem to take into account maps properly when using set.

Thanks for the detective work. I appreciate that.

All 9 comments

Is it selectedAnswers? It shows up empty even though you know you have data within it?

Typescript disappears in runtime, so I don't think it's a typescript issue.

es6 maps work fine... i just tested this:

      const x = new Map<string, string>()
      x['hello'] = 'world'
      console.tron.log({ yo: x })

And it logs properly.

image

I notice this is in your subscriptions... are you using mobx-state-tree or redux or something else?

I'm using redux

Can you post some more code? Maybe your reducer?

Are you sure you're saving stuff in that map? If you were to log out the length of the map, is it > 0?

I tried with a simple

const x = new Map<string, string>();
x.set('hello', 'world');
Reactotron.log({ yo: x });

and get this log in Reactotron:

image

ah, it works if I use x['hello'] = 'world';
but I get this TS and TSlint errors:

image

If I do this:

const map = new Map<string, string>([['hello', 'world']]);
Reactotron.log({ map });
const hello = map.get('hello');
Reactotron.log({ hello });

I get this:

image

But if I use the regular console.log():

const map = new Map<string, string>([['hello', 'world']]);
console.log({ map });
const hello = map.get('hello');
console.log({ hello });

I see the object:

image

Ya something is off here for sure. The way we serialize doesn't seem to take into account maps properly when using set.

Thanks for the detective work. I appreciate that.

This is _kinda_ fixed in the latest version of reactotron-core-client (and thus reactotron-react-native and reactotron-react-js). I say kinda because it ships each map item as an array with the first item being the key and the second being the value. There might be a good argument for trying to detect a map better but I am calling this "good enough" for now.

I've had the same problem with core React state. Changes to a Map (saved to state) don't trigger re-renders like primitive data, it compares the references. The code had to look like this...

const [myList, setMyList] = useState<Map<string, MyThing>>(new Map())

const updateMap = (k: string, v: Thing) => {
  setMyList(myList.set(k, v))
  forceUpdate()
}

const [, updateState] = React.useState<object>()
const forceUpdate = useCallback(() => updateState({}), [])
Was this page helpful?
0 / 5 - 0 ratings

Related issues

fkereki picture fkereki  路  3Comments

Anahkiasen picture Anahkiasen  路  5Comments

wilr picture wilr  路  3Comments

sylar picture sylar  路  4Comments

itaied246 picture itaied246  路  4Comments