How to embed another react component inside a reactcomponent?

hello im a fp noob and just wanted to dip my toes in using reactjs with purescript. below i have a snippet of a react component inside another react component. Im trying to convert this into purescript but don’t know how to do it. I have both components coming in through FFI which seems to be working fine. I also took a look at the docs and reccommended tutorials but cant find how to do it but there seems to be a function called reactcomponentWithChildren that i have no idea how to use. any help is appreciated.

    <MapContainer center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false}
     style={{ height:"400px",backgroundColor:"red",marginTop:"80px", marginBottom:'90px'
    }}>
  <TileLayer
    attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
  <Marker position={[51.505, -0.09]}>
        <Popup>
      A pretty CSS3 popup. <br /> Easily customizable.
        </Popup>
          </Marker>
            </MapContainer>

module Foreign.LeafletMap
  ( marker
  , popup
  , tileLayer
  )
  where
import Data.Maybe (Maybe(..))
import React.Basic.Hooks (ReactComponent)
foreign import leafletMap
  :: ReactComponent
    { center :: Array Number
    , zoom :: Int
    , scrollWheelZoom :: Boolean
    }
foreign import tileLayer :: ReactComponent
                            {
                              attribution :: String
                              , url :: String                          
                            }
module Main
  ( main
  , mkRandomBox
  )

where 
import Prelude
import Data.Maybe (Maybe(..))
import Effect (Effect)
import Effect.Exception (throw)
import Effect.Random (randomInt)
import Foreign.ReactPlayer (reactPlayer)
import Foreign.LeafletMap (leafletMap, tileLayer, marker, popup)
import React.Basic.DOM (css)
import React.Basic.DOM as R
import React.Basic.DOM.Client (createRoot, renderRoot)
import React.Basic.Events (handler_)
import React.Basic.Hooks (Component, component, element, useState', (/\), reactComponentWithChildren)
import React.Basic.Hooks as React
import Web.DOM.NonElementParentNode (getElementById)
import Web.HTML (window)
import Web.HTML.HTMLDocument (toNonElementParentNode)
import Web.HTML.Window (document)-- | Find the element with `app` id, that we declared in `index.html`.
-- | Create and render a component tree into this element,
-- | Or crash in case we messed up during the setup.
main :: Effect Unit
main = do
  doc <- document =<< window
  container <- getElementById "app" $ toNonElementParentNode doc
  case container of
    Nothing -> throw "Could not find container element"
    Just c -> do
      leaflet <- reactComponentWithChildren "Leaflet"  \_ -> React.do
                          pure $  element leafletMap
                                      { center: [100.0, 100.0]
                                      , scrollWheelZoom: false
                                      , zoom: 50
                                      -- , style: css { height:"400px"
                                      --              , backgroundColor:"red"
                                      --              , marginTop:"80px"
                                      --              , marginBottom:"90px"
                                      --              },
                                    -- , children: [ 
                                    --     element tileLayer { attribution: "&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors"
                                    --             , url:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                                    --             }
                                    -- ]
                                      }
                          
      reactRoot <- createRoot c
      renderRoot reactRoot (leaflet )



1 Like

Welcome @nostalgic!
I think you’re really close. In React, style and children are sort of implicit props for any component, but in PureScript, a ReactComponent can’t take in any props that aren’t explicit. I haven’t tried this in an editor to see if it works, but if you just edit your leafletMap definition to include , children :: Array JSX, style :: CSS, then I believe everything will work as you expect.

ill give it a try, thanks for the tip.

for anyone curious i got it to work albiet the other parts to make the map work correctly are yet to be implemented. its for sure completely done incorrectly without the proper idioms but it was just to learn so take it as is. thanks again @ntwilson. the code is denoted below:


module Foreign.LeafletMap
  ( marker
  , popup
  , tileLayer
  , mapContainer
  )
  where
import Data.Maybe (Maybe(..))
import React.Basic.Hooks (ReactComponent)
import React.Basic (JSX)
import React.Basic.DOM (CSS)
foreign import mapContainer :: ReactComponent
    { center :: Array Number
    , zoom :: Int
    , scrollWheelZoom :: Boolean
    , children ::  Array JSX
    , style :: CSS
    }
foreign import tileLayer :: ReactComponent
                            {
                              attribution :: String
                              , url :: String                          
                            }
foreign import marker :: ReactComponent
                         {
                          
                         }
foreign import popup :: ReactComponent
                        {
                          
                        }



module Main where
import Prelude
import Data.Maybe (Maybe(..))
import Effect (Effect)
import Effect.Exception (throw)
import Effect.Random (randomInt)
import Foreign.ReactPlayer (reactPlayer)
import Foreign.LeafletMap (mapContainer, tileLayer)
import React.Basic.DOM (css, CSS)
import React.Basic.DOM as R
import React.Basic.DOM.Client (createRoot, renderRoot)
import React.Basic.Events (handler_)
import React.Basic.Hooks (Component, component, element, useState', (/\), ReactComponent, reactComponent, JSX)
import React.Basic.Hooks as React
import Web.DOM.NonElementParentNode (getElementById)
import Web.HTML (window)
import Web.HTML.HTMLDocument (toNonElementParentNode)
import Web.HTML.Window (document)-- | Find the element with `app` id, that we declared in `index.html`.
-- | Create and render a component tree into this element,
-- | Or crash in case we messed up during the setup.
main :: Effect Unit
main = do
  doc <- document =<< window
  container <- getElementById "app" $ toNonElementParentNode doc
  case container of
    Nothing -> throw "Could not find container element"
    Just c -> do
      leaf <- mkLeaflet 
      reactRoot <- createRoot c
      renderRoot reactRoot (element leaf {})-- | An effectful function that creates a react component without any props.

mkLeaflet :: Effect (ReactComponent  {})
mkLeaflet = do
  reactComponent "Leaflet" \_ -> React.do
    pure $ element mapContainer { center: [100.0, 100.0]
                        , scrollWheelZoom: false
                        , zoom: 50
                        , style: css { height:"400px"
                                      , backgroundColor:"red"
                                      , marginTop:"80px"
                                      , marginBottom:"90px"
                                      }
                        , children:  [ element tileLayer { attribution: "&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors"
                                      , url:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                                        }
                                    ]
                          } 
    

1 Like

fixed the rest of it since it seemed wrong not to get it functioning.

2 Likes