Skip to content
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

Habitat incompatible with {children}? #29

Closed
ryanpcmcquen opened this issue Jan 23, 2018 · 6 comments
Closed

Habitat incompatible with {children}? #29

ryanpcmcquen opened this issue Jan 23, 2018 · 6 comments
Labels

Comments

@ryanpcmcquen
Copy link
Contributor

I have a button that takes {children} as text content (rather than having a separate text prop). Is this possible in Habitat, or does everything that is rendered need to be a prop?

Source for the button is here:
https://github.com/ryanpcmcquen/react-habitat-poc/blob/master/source/components/Button/Button.js

@jennasalau
Copy link
Contributor

Hey Ryan,

Children is an interesting one. It gets tricky because React Habitat essentially only provides a React DOM interface from HTML. Now React children expects type React Component/Node which we don't have in HTML. Only DOM Elements. In fact, the inner HTML is getting used as fallbacks by others.

Fair enough you are only trying to pass in a text node, but it gets much more complicated if it was another React component. For this reason I'm reluctant to add direct support for children as its a very "React" thing and not so much a "React DOM / Habitat" thing. I would rather this library stay dumb to React itself.

In saying that though, you have a few options:

Option 1
children is available on props anyway so there is no reason you can't do the following. The only caveat is obviously it needs to be a text node. (I haven't tested this btw).

<div data-component="Button" data-prop-children="My Button Text" />

Option 2
You change your Button component slightly to accept children OR text prop.

render() {
    return <a>{this.props.children || this.props.text}</a>;
}

Then

<div data-component="Button" data-prop-text="My Button Text" />

Option 3
You use the proxy prop to read the innerHTML from the target element and turn it into a React component.

eg in your Button (again this is very untested, just brain dumping)

constructor(props) {
    const children = React.createElement(props.proxy.innerHTML);
}

You might have better millage with something like https://roman01la.github.io/html-to-react-components/

I would still advise against option 3 anyway as it tightly couples your components to React Habitat. This should be a last resort.

@ryanpcmcquen
Copy link
Contributor Author

@jennasalau, thank you for the thorough response. It seems that option 1 would be the best, since it keeps the components from having extra logic, merely to work inside Habitat. As a random question, how would you approach building a slideshow component in React Habitat? For example, one that could take different types of cards (photo, video, product) ...

@jennasalau
Copy link
Contributor

jennasalau commented Jan 23, 2018

No problem :)

I would get the backend to pass the slide show "data" through in JSON format

For example

{
    "slides": [
          {
               "media": "/banner.png",
               "title": "Cool Banner",
               "description": "A nice description",
               "type": "IMAGE",
               "href": "/some-link",
               "meta": {}
          },
          {
               "media": "http://youtube.com/videoid",
               "title": "Cool Video",
               "description": "A nice description",
               "type": "VIDEO",
               "href": "/some-link",
               "meta": {}
          },
          {
               "media": "/product-image.png",
               "title": "Check out this product",
               "description": "A nice description",
               "type": "PRODUCT",
               "href": "/some-link",
               "meta": {
                     "price": 29.99
               }
          },
    ]
}

I would then have a specific component that converts that JSON into a React slideshow. This one i would expose to React Habitat also.

import SomeSlideShowLibarary from 'some-slide-show-library';
import Card from './Card';
import Video from './Video';
import Product from './Product';

class SlideShow extends React.Component {
     renderItems() {
         // data being the json parsed data passed in by React Habitat or a React Parent
         return this.props.data.map((slide) => {
             switch (slide.type) {
                  case 'IMAGE':
                       return <Card text={slide.title} img={slide.media} />;
                  case 'VIDEO':
                       return <Video text={slide.title} src={slide.media} />;
                  case 'PRODUCT':
                       return <Product text={slide.title} price={slide.meta.price} />;
                  default:
                      console.error('I don't know that type', slide.type);
                      return null;
             }
         });
     }      

     render() {
          return (
               <SomeSlideShowLibarary>{this.renderItems()}</SomeSlideShowLibarary>
          );
     }
}

Thats how i would approach it anyway.

@ryanpcmcquen
Copy link
Contributor Author

You rock @jennasalau, thank you for sharing your knowledge!

@ryanpcmcquen
Copy link
Contributor Author

For anyone else who is curious about this problem, we found a way to handle child components using React Habitat in slt-ui.

@fsvaren
Copy link

fsvaren commented Jan 7, 2023

Has habitat got support for this yet? I am running into some strange issues when using react-slider, and I suspect it is related because it works well in standard preact.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants