Passing on map properties from the parent to the children

1795
8
Jump to solution
11-22-2022 10:39 AM
LefterisKoumis
Occasional Contributor III

Hello. A React newbie here.

I have a long script and for the purpose of managing the code I split it to different components. 

I have the widget (parent) component that I store the selected map in the jimuMapView.

Then, I have the children components that need to use the props of the jimuMapView so they add layers and graphics to that map, or other actions like zoom and so forth.

So, my question is how in the children components I can access the jimuMapView from the parent to add the layers?

None of the documentation or examples in ESRI address this scenario.

@RobertScheitlin__GISP , @Grant-S-Carroll or anyone else? Thank you.

 

 

 
activeViewChangeHandler = (jmv: JimuMapView) => {
    if (jmv) {this.setState({ jimuMapView: jmv }); }
  };


<div className="widget-addLayers jimu-widget p-2">
        {this.props.hasOwnProperty("useMapWidgetIds") &&
          this.props.useMapWidgetIds &&
          this.props.useMapWidgetIds[0] && (
            <JimuMapViewComponent
              useMapWidgetId={this.props.useMapWidgetIds?.[0]}
              onActiveViewChange={this.activeViewChangeHandler}
            />
          )}

 

  

0 Kudos
2 Solutions

Accepted Solutions
Grant-S-Carroll
Esri Contributor

Hi There

There are a couple of ways of achieving this, depending of what your are trying to do in your child component. 

1. You can simply pass the jimuMapView through in to your child component, by making the mapView a prop of the child component, see below.

In your child component, create an interface for the props.

GrantSCarroll_0-1669144339330.png

Then reference these in the class/function depending on what pattern you are using.

GrantSCarroll_1-1669144381068.png

You can then access the map via this.props.mapView

GrantSCarroll_2-1669144471729.png

 

2. The second appropach is ito pass in functions from the parent component that act on the mapView.

As before within your props interface in your  child component, add in a reference to the function.

GrantSCarroll_3-1669144568028.png

 Then when you need to call this function within the child, call this.props.<functionName>

GrantSCarroll_4-1669144721094.png

 

Within the parent component, it looks like this.

GrantSCarroll_5-1669144830107.png

 In the example above, the parent component is actual a child component of widget.tsx, so I have passed the mapView down several times. 

Hopefully that all makes sense?

Cheers

 

 

 

 

 

View solution in original post

0 Kudos
Grant-S-Carroll
Esri Contributor

You just need to make sure that you have declared the mapView as the right type. Its not a jimuMapView you are assigning the view property of the jimuMapView, which can either be a MapView or a SceneView.

GrantSCarroll_0-1669688823355.png

Component did mount will only fire once, when the component is mounted in to the DOM. At that stage, the map will most likely not have loaded, hence why using activeViewChange is the best place to capture when the map has loaded.

View solution in original post

8 Replies
Grant-S-Carroll
Esri Contributor

Hi There

There are a couple of ways of achieving this, depending of what your are trying to do in your child component. 

1. You can simply pass the jimuMapView through in to your child component, by making the mapView a prop of the child component, see below.

In your child component, create an interface for the props.

GrantSCarroll_0-1669144339330.png

Then reference these in the class/function depending on what pattern you are using.

GrantSCarroll_1-1669144381068.png

You can then access the map via this.props.mapView

GrantSCarroll_2-1669144471729.png

 

2. The second appropach is ito pass in functions from the parent component that act on the mapView.

As before within your props interface in your  child component, add in a reference to the function.

GrantSCarroll_3-1669144568028.png

 Then when you need to call this function within the child, call this.props.<functionName>

GrantSCarroll_4-1669144721094.png

 

Within the parent component, it looks like this.

GrantSCarroll_5-1669144830107.png

 In the example above, the parent component is actual a child component of widget.tsx, so I have passed the mapView down several times. 

Hopefully that all makes sense?

Cheers

 

 

 

 

 

0 Kudos
LefterisKoumis
Occasional Contributor III

THank you. I followed the first method I am almost there.

In the child component, I console log the 

LefterisKoumis_0-1669168484701.png

and I get this:

LefterisKoumis_1-1669168570327.png

I want to access the this.props.mapView.view which it is a property because under it is the map module.

However, when I console log

LefterisKoumis_3-1669168912538.png

I get the red underline that the view is not a property of the mapView, however the console outputs the x coordinate. Why does it works? I was able to add a layer using the this.props.mapView.view.map.add

This is confusing. Thank you.

 

 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

@LefterisKoumis looks like you are passing the jimuMapView to your component and not the jimuMapView.view. I use method one that Grant suggested in most of my custom components and pass the actual view object and don't have any problems.

LefterisKoumis
Occasional Contributor III

@RobertScheitlin__GISP  After I was passing the  jimuMapView.view to the the child component

 <div>{<ChildComponent mapView={this.state.jimuMapView.view} />}</div>

I am getting the error "Cannot read properties of null (reading 'view')" at runtime. of the line above. It seems that there is async error. The 'this.state.jimuMapView' seems to be null.

To address it, I used this from the FeaturePanel, to no avail:

activeViewChangeHandler = (jimuMapView: JimuMapView) => {
    if (null === jimuMapView || undefined === jimuMapView) {
      this.setState({ jimuMapView: null });
      return; //skip null
    }
    this.setState({ jimuMapView: jimuMapView });
  };

How can the rendering of the component be delayed until the jimuMapView is not null.

0 Kudos
Grant-S-Carroll
Esri Contributor

Hi, apologies for lack of response, I'm in the throws of moving houses and islands. What you can do is store the actual mapView in state, not the jimuMapView, so in the onActiveViewChange do something like this.

 

 

  onActiveViewChange = (jimuMapView: JimuMapView) => {
        if (!(jimuMapView && jimuMapView.view)) {
            return;
        }
        this.setState({ mapView:jimuMapView.view });
 }

 

 

Then within your child component, you will need to handle the case where the view is null, but it should prevent the issues you are facing with the null value, as the re-render will occur anytime the state is updated.

 

Hope that helps.

 

Cheers

0 Kudos
LefterisKoumis
Occasional Contributor III

THank you. 

I got this error.

LefterisKoumis_0-1669686389622.png

Question. Should we use the componentDidMount to update the jimuMapView state to avoid async  errors?

0 Kudos
Grant-S-Carroll
Esri Contributor

You just need to make sure that you have declared the mapView as the right type. Its not a jimuMapView you are assigning the view property of the jimuMapView, which can either be a MapView or a SceneView.

GrantSCarroll_0-1669688823355.png

Component did mount will only fire once, when the component is mounted in to the DOM. At that stage, the map will most likely not have loaded, hence why using activeViewChange is the best place to capture when the map has loaded.

LefterisKoumis
Occasional Contributor III

Yes, you are correct. What a novice mistake. Thank you.

0 Kudos