-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(MapTemplate): convert to TS #1265
Conversation
mapViewport: { | ||
minZoom: number; | ||
maxZoom: number; | ||
bearing?: number | undefined | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about these typings-- I think we need to include undefined
and null
because the INITIAL_STATE
defined in the map
duck doesn't define values for bearing
, zoom
, latitude
, or longitude
(we do this since we don't want to introduce an arbitrary initial map position or zoom).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see a couple issues here.
- It doesn't seem like we need to include both
undefined
andnull
. I think we should set it to null, and keep the type as nullable, or pick a default value. And I think it would be cleaner to explicitly define these values in our initial viewport state, like so:
initialMapViewport: {
minZoom: 0,
maxZoom: 18,
bearing: null,
// or set it to a value, and avoid making this nullable:
// bearing: -60,
pitch: null,
// etc
}
- It might be out of scope of this PR, but why we are storing the
INITIAL_STATE
of our mapViewport in ourmap
duck? It seems redundant to load it inapp.tsx
, and then read/set it to our MapTemplate component state. Can we pass the initial state as a prop from App to MapTemplate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd rather set the map viewport state to initial numerical values, which seems like it would be cleaner.
The idea behind initialMapViewport
was to keep track of both the default map viewport as set in the config, but also the viewport when navigating away from the MapTemplate
. That way, the last viewport can be restored when returning to the MapTemplate
after MapTemplate
re-mounts.
Though we could also keep this state in App
's component state, and update it via a callback from MapTemplate
when it unmounts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though we could also keep this state in App's component state, and update it via a callback from MapTemplate when it unmounts.
Seems like a reasonable intermediate solution. But I believe a more thorough solution, however, is to use the Context API: https://reactjs.org/docs/context.html
That should give us the persistence that global state provides, without the performance drawbacks that Redux entails, while also avoiding the prop-drilling that component state entails as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for porting this module!
I left some feedback - lmk what you think 👍
@@ -356,17 +430,21 @@ class MapTemplate extends Component { | |||
|
|||
render() { | |||
return ( | |||
<> | |||
<div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this changed to a div
?
I suspect you might be having import issues related to the /** @jsx jsx */
pragma, which prevents Babel from transpiling the <>
shorthand into <Fragment>
. Note that you can work around this issue by importing Fragment
and writing out <Fragment>
.
mapViewport: { | ||
minZoom: number; | ||
maxZoom: number; | ||
bearing?: number | undefined | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see a couple issues here.
- It doesn't seem like we need to include both
undefined
andnull
. I think we should set it to null, and keep the type as nullable, or pick a default value. And I think it would be cleaner to explicitly define these values in our initial viewport state, like so:
initialMapViewport: {
minZoom: 0,
maxZoom: 18,
bearing: null,
// or set it to a value, and avoid making this nullable:
// bearing: -60,
pitch: null,
// etc
}
- It might be out of scope of this PR, but why we are storing the
INITIAL_STATE
of our mapViewport in ourmap
duck? It seems redundant to load it inapp.tsx
, and then read/set it to our MapTemplate component state. Can we pass the initial state as a prop from App to MapTemplate?
Co-Authored-By: goldpbear <goldpbear@users.noreply.github.com>
Co-Authored-By: goldpbear <goldpbear@users.noreply.github.com>
src/base/static/components/app.tsx
Outdated
@@ -169,18 +168,44 @@ declare const Mapseed: any; | |||
// 'process' global is injected by Webpack: | |||
declare const process: any; | |||
|
|||
interface State { | |||
export interface IMapViewport { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're exporting this interface, I thought it would be useful to start adopting the I
syntax for interfaces to make it clearer when an interface is being imported into another module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered using the I
prefix, and decided not to do it based on some guidelines I found here: https://angular.io/guide/styleguide#interfaces and here: https://stackoverflow.com/questions/31876947/confused-about-the-interface-and-class-coding-guidelines-for-typescript/41967120#41967120
But I don't have a strong opinion on it. So feel free to stick with what you think is more comfortable. I found a full flame war on the topic here: microsoft/TypeScript-Handbook#121
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, well I guess I'm not surprised it's controversial. Within a module it seems like overkill, but when exporting interfaces I thought it would make things clearer. But that's based on my one-day experience with TS.
Maybe I'll just leave it for now, and if it turns out to be silly we can revert the I
syntax.
@@ -12,6 +14,7 @@ import LeftSidebar from "../organisms/left-sidebar"; | |||
import RightSidebar from "../organisms/right-sidebar"; | |||
import GeocodeAddressBar from "../organisms/geocode-address-bar"; | |||
|
|||
import { IMapViewport } from "../app"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is creating a circular dependency, which we should avoid: https://medium.com/content-uneditable/circular-dependencies-in-javascript-a-k-a-coding-is-not-a-rock-paper-scissors-game-9c2a9eccd4bc
I'm not sure where to put IMapViewport
, but we can consider making a map.d.ts
file alongside our map duck, and then import it from there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make more sense to define it in an app.d.ts file alongside the App
component? The map duck doesn't store the viewport anymore, so it might be confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "d.ts" file is used to provide typescript type information about an API that's written in JavaScript, so app.d.ts
wouldn't make sense.
It seems like the most proper solution here would be to put our MapViewport in a Context. Although we aren't using the Context API yet, we can consider making a new static/contexts/
dir, and putting map.tsx
file under that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we create something like an interfaces.ts
file and put it in src/base/static
instead?
My understanding of the Context API is that it's for sharing state among numerous components at different levels of the hierarchy. Since the map viewport is only used by a couple of components it seems like it might be overkill here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My concern is that interfaces.ts
would become a dumping grounds, and it's not clear what kinds of interfaces will be stored there. As we port over to TS, we're going to defining lots of interfaces.
I'm not too familiar with Context API, but it seems like a reasonable use case since we're drilling our MapViewport from App > MapTemplate > MainMap, and perhaps other components as well, like the Drawing component, Story Sidebar, etc.
But feel free to use your judgement 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I'm not sure what the best thing to do is. Maybe to keep things simple in this PR I'll just define a separate interface in map.tsx
, which actually might be appropriate because technically the initialMapViewport
and mapViewport
differ slightly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And, I guess since we're not sharing interfaces I'll do away with the I
syntax too :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good 👍
Let's make sure to fix that circular dep first before merging, though
Addresses: https://github.com/jalMogo/mgmt/issues/275