hyperx icon indicating copy to clipboard operation
hyperx copied to clipboard

How to pass function as child?

Open Siilwyn opened this issue 5 years ago • 7 comments

:wave: hi, wondering how to pass a function to a component. Trying to use the Query component from react-apollo.

const hyperx = require('hyperx');
const { Query } = require('react-apollo');
const gql = require('graphql-tag');
const { createElement } = require('react');

const hx = hyperx(createElement);

hx`<${Query}
  query=${gql`
    {
      // query here
    }
  `}
>
  ${({ loading, error, data }) => {
    // function content here
  }}
</${Query}>`

Returns:

Failed prop type: Invalid prop `children` of type `array` supplied to `Query`, expected `function`.
    in Query

Siilwyn avatar Aug 08 '18 15:08 Siilwyn

@goto-bus-stop @substack is passing a function as a child possible at all?

Siilwyn avatar Nov 13 '18 21:11 Siilwyn

I don't think so. it might work if you pass it as the children=${fn} prop instead though

goto-bus-stop avatar Nov 13 '18 21:11 goto-bus-stop

@goto-bus-stop ah okay, thank you for you reply!

That's a bummer, I've been looking around for a JSX alternative because I don't like the magic, seems that there is no replacement out there yet.

Siilwyn avatar Nov 13 '18 21:11 Siilwyn

This isn't restricted to apollo btw. I've seen react components accept functions before. Just tested with GatsbyJS too:

import React from 'react';
import { StaticQuery, graphql } from 'gatsby';
import hyperx from 'hyperx';

const hx = hyperx(React.createElement);

export default ({ children }) => hx`
  <${StaticQuery}
    query=${graphql`
      {
        site {
          siteMetadata {
            title
          }
        }
      }
    `}
    render=${() => {}}
  />
`;

Interestingly enough this gives a different error though: Objects are not valid as a React child (found: object with keys {query, render}). If you meant to render a collection of children, use an array instead.. Probably because this is a self closing tag.

Siilwyn avatar Nov 13 '18 22:11 Siilwyn

Funny thing is the above is a pretty bad example, I would say the following using just createElement is even more readable:

import { createElement } from 'react';
import { StaticQuery, graphql } from 'gatsby';

export default ({ children }) => createElement(
  StaticQuery,
  {
    query: graphql`
      {
        site {
          siteMetadata {
            title
          }
        }
      }
    `,
    render: () => {},
  }
);

Though mixing hyperx and the use of createElement could be very confusing to some developers. I'll keep poking. :)

Siilwyn avatar Nov 13 '18 22:11 Siilwyn

We could probably loosen the type check to allow function children, but I also agree that using createelement is nicer. I'd alias it to something like h and use it for all custom components, then just use hyperx for the native HTML nodes. you could also look into hyperscript (there is a react version of it but I forgot the name) if you haven't already, it's like a fancier createElement function, no template strings

goto-bus-stop avatar Nov 13 '18 22:11 goto-bus-stop

Hmm loosening the type check could be desirable because I'm not sure if in all cases createElement is nicer... Thanks for the tip, I know hyperscript but prefer hyperx because it's closer to HTML.

Siilwyn avatar Nov 14 '18 20:11 Siilwyn