Binding Question Help..!

Hi, I’m a newbie to ReScript. I’m trying to bind and use “react-native-skeleton-placeholder” with react native, and I have a question.

The types are as follows

declare type SkeletonPlaceholderItemProps = ViewStyle & {
    style?: StyleProp<ViewStyle>;
    children?: React.ReactNode;
};
declare const SkeletonPlaceholder: React.FC<SkeletonPlaceholderProps> & {
    Item: React.FC<SkeletonPlaceholderItemProps>;
};
export default SkeletonPlaceholder;

And you can use it like this

import SkeletonPlaceholder from 'react-native-skeleton-placeholder'

function Skeleton() {
  return (
    <SkeletonPlaceholder borderRadius={4}>
      <SkeletonPlaceholder.Item flexDirection="row" alignItems="center">
        <SkeletonPlaceholder.Item width={60} height={60} borderRadius={50} />
        <SkeletonPlaceholder.Item marginLeft={20}>
          <SkeletonPlaceholder.Item width={120} height={20} />
          <SkeletonPlaceholder.Item marginTop={6} width={80} height={20} />
        </SkeletonPlaceholder.Item>
      </SkeletonPlaceholder.Item>
    </SkeletonPlaceholder>
  )
}

For SkeletonPlaceholder, I can bind it with “default” when bind it, the problem is when bind SkeletonPlaceholder.Item.

The reason is that the Item is not exported separately, and I need to access it as SkeletonPlaceholder.Item, so I’m wondering how to do the binding in reScript in this situation.

If you have any ideas, please help!

1 Like

There’s probably a better way to do this, but if you’re sure you are always using the SkeletonPlaceholder.Item only inside a SkeletonPlaceholder, then you can take advantage of the fact that ReScript outputs the ES6 module import code in a certain way:

import ReactNativeSkeletonPlaceholder from "react-native-skeleton-placeholder";

Given that the output ES6 code will have that import, then we can refer to it when binding to the Item component:

// For demo only, normally this is a file e.g. SkeletonPlaceholder.res
module SkeletonPlaceholder = {
  @module("react-native-skeleton-placeholder")
  @react.component
  external make: (~borderRadius: int, ~children: React.element) => React.element =
    "default"

  module Item = {
    @react.component
    external make: React.element => (~flexDirection: string) => React.element =
      // This takes advantage of the import bringing the name 'ReactNativeSkeletonPlaceholder' into scope
      "ReactNativeSkeletonPlaceholder.Item"
  }
}

let test =
  // This will cause ReScript to import the ES6 module
  <SkeletonPlaceholder borderRadius=4>
    <SkeletonPlaceholder.Item flexDirection="row" />
  </SkeletonPlaceholder>

Of course, this can break pretty easily:

  1. If ReScript decides to change its naming convention for imported ES6 modules
  2. If the module name itself changes

You should assess the risks of these two events before using this approach.

1 Like

Update: this is probably a much better way: How do I write a binding that imports a function from the default module? - #11 by DZakh

1 Like