How to compose props across component in reason-react bindings?

梦想的初衷 提交于 2021-02-07 20:22:08

问题


I am currently writing a material-UI reason-react binding and I want to know how I can re-use previously define Props.

The Select component spreads all of the Input props into itself, in the underlying react-js lib. this is done by spreading props however this is discouraged in ReasonML as typings are lost.

As a temporary solution, I have copied the props from one to another but this is not scalable. I would appreciate if someone could suggest what is the correct way of doing this in Reason-React?

Thanks

Input module definiton:

module Input = {
  [@bs.module "material-ui/Input"] external reactClass : ReasonReact.reactClass = "default";
  let make =
      (
        ~disableUnderline: option(bool)=?,
        ~disabled: option(bool)=?,
        ~error: option(bool)=?,
        ~autoFocus: option(bool)=?,
        ~fullWidth: option(bool)=?,
        ~style: option(ReactDOMRe.style)=?,
        ~value: option(string)=?,
        ~onChange: option((ReactEventRe.Form.t => unit))=?,
        ~placeholder: option(string)=?,
        ~className: option(string)=?,
        ~inputType: option(string)=?,
        children
      ) =>
    ReasonReact.wrapJsForReason(
      ~reactClass,
      ~props=
        Js.Nullable.(
          {
            "disableUnderline": unwrap_bool(disableUnderline),
            "disabled": unwrap_bool(disabled),
            "error": unwrap_bool(error),
            "fullWidth": unwrap_bool(fullWidth),
            "autoFocus": unwrap_bool(autoFocus),
            "style": from_opt(style),
            "placeholder": from_opt(placeholder),
            "className": from_opt(className),
            "type": from_opt(inputType),
            "value": from_opt(value),
            "onChange": from_opt(onChange)
          }
        ),
      children
    );
};

Select module definiton:

    module Select = {
  [@bs.module "material-ui/Select"] external reactClass :  ReasonReact.reactClass = "default";
  let make =
      (
        ~autoWidth: option(bool)=?,
        ~classes: option(Js.t({..}))=?,
        ~className: option(string)=?,
        ~displayEmpty: option(bool)=?,
        ~input: option(ReasonReact.reactElement)=?,
        ~inputClasses: option(Js.t({..}))=?,
        ~native: option(bool)=?,
        ~multiple: option(bool)=?,
        ~menuProps: option(Js.t({..}))=?,
        ~renderValue: option((unit => unit)),
        ~value: option('a)=?,
        ~style: option(ReactDOMRe.style)=?,
        /* Input Props*/
        ~disableUnderline: option(bool)=?,
        ~disabled: option(bool)=?,
        ~error: option(bool)=?,
        ~autoFocus: option(bool)=?,
        ~fullWidth: option(bool)=?,
        ~value: option(string)=?,
        ~onChange: option((ReactEventRe.Form.t => unit))=?,
        ~placeholder: option(string)=?,
        ~className: option(string)=?,
        ~inputType: option(string)=?,
        children
      ) =>
    ReasonReact.wrapJsForReason(
      ~reactClass,
      ~props=
        Js.Nullable.(
          {            
            "autoWidth": unwrap_bool(autoWidth),
            "classes": from_opt(classes),
            "className": from_opt(className),
            "displayEmpty": unwrap_bool(displayEmpty),
            "input": from_opt(input),
            "InputClasses": from_opt(inputClasses),
            "native": unwrap_bool(native),
            "multiple": unwrap_bool(multiple),
            "MenuProps": from_opt(menuProps),
            "renderValue": from_opt(renderValue),
            "value": from_opt(value),
            "style": from_opt(style),
            /* Input Props*/
            "disableUnderline": unwrap_bool(disableUnderline),
            "disabled": unwrap_bool(disabled),
            "error": unwrap_bool(error),
            "fullWidth": unwrap_bool(fullWidth),
            "autoFocus": unwrap_bool(autoFocus),
            "style": from_opt(style),
            "placeholder": from_opt(placeholder),
            "className": from_opt(className),
            "type": from_opt(inputType),
            "value": from_opt(value),
            "onChange": from_opt(onChange)
          }
        ),
      children
    );
};

回答1:


You can use currying and Js.Obj.assign to achieve this:

let common = (reactClass, props, ~commonProp1, ~commonProp2, children) =>
  ReasonReact.wrapJsForReason(
    ~reactClass,
    ~props=Js.Obj.assign(props, {
      "commonProp1": commonProp1,
      "commonProp2": commonProp2
    }),
    children
  );

module Input = {
  [@bs.module "material-ui/Input"] external reactClass :  ReasonReact.reactClass = "default";
  let make = (~inputProp1, ~inputProp2) => common(reactClass, {
    "inputProp1": inputProp1,
    "inputProp2": inputProp2
  });
};

module Select = {
  [@bs.module "material-ui/Select"] external reactClass :  ReasonReact.reactClass = "default";
  let make = (~selectProp1, ~selectProp2) => common(reactClass, {
    "selectProp1": selectProp1,
    "selectProp2": selectProp2
  });
};

In each make function common is partially applied, and due to currying will "extend" the make function with its own arguments. In effect, the type signature of e.g. Input.make will be ~inputProp1 => ~inputProp2 => ~commonProp1 => ~commonProp2 => ....



来源:https://stackoverflow.com/questions/47134445/how-to-compose-props-across-component-in-reason-react-bindings

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!