【问题标题】:Binding to Higher Order Component from aws-amplify从 aws-amplify 绑定到高阶组件
【发布时间】:2019-08-18 21:48:25
【问题描述】:

bucklescript 寻找什么来满足以下示例产生的Functions are not valid as a React child. 错误。

我从aws-amplify-react 绑定到withAuthenticator

[@bs.deriving abstract]
type props = {
  [@bs.as "Comp"]
  comp: React.element,
  [@bs.optional] includeGreetings: bool,
};

[@genType.import ("aws-amplify-react", "withAuthenticator")] [@react.component]
external make:(
    ~props:props,
  ) => React.element = "withAuthenticator";
let default = make;

Demo.re我使用绑定如下:

let props = {
  WithAuthenticator.props(
    ~comp={
      <App />;
    },
    ~includeGreetings=true,
    (),
  );
};
Js.log(props);
[@react.component]
let app = () => <WithAuthenticator props />;

然后在App.js 我使用Demo.re 像这样:

import Amplify from 'aws-amplify';
import {app as App } from './Demo.bs';
import awsconfig from './aws-exports';
import './App.css';
Amplify.configure(awsconfig);

export default App;

这会产生以下错误:

 Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
    in withAuthenticator (created by Demo$app)
    in Demo$app (at src/index.js:7)

我想了解这意味着什么,以便在它再次出现时进行处理。

这是编译好的扣脚本代码在Demo.bs.js:

// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';

var React = require("react");
var App$ReactHooksTemplate = require("./App.bs.js");
var WithAuthenticator$ReactHooksTemplate = require("../aws/WithAuthenticator.bs.js");

var props = {
  Comp: React.createElement(App$ReactHooksTemplate.make, { }),
  includeGreetings: true
};

console.log(props);

function Demo$app(Props) {
  return React.createElement(WithAuthenticator$ReactHooksTemplate.make, {
              props: props
            });
}

var app = Demo$app;

exports.props = props;
exports.app = app;
/* props Not a pure module */

可以在here 找到此问题的重现。

更新:

在这里,我试图跟进@glennsl 的 cmets/answer 下面。

// define a type modeling what `withAuthenticator` is expecting
[@bs.deriving abstract]
type props = {
  [@bs.as "Comp"]
  comp: React.element,
  [@bs.optional]
  includeGreetings: bool,
};
// use bs.module instead of gentype
[@bs.module ("aws-amplify-react", "withAuthenticator")]
external withAuthenticator: props => React.component(props) =
  "withAuthenticator";
module AppWithAuthenticator = {
  [@bs.obj]
  external makeProps:
    (~children: 'children, unit) => {. "children": 'children} =
    "";
  let make = props => withAuthenticator(props);
};

这可能是它的使用方式,但不能编译。


module AppWithAuth = {
  let props = {
    props(
      ~comp={
        <App />;
      },
      ~includeGreetings=true,
      (),
    );
  };
  [@react.component]
  let make = () => {
    <AppWithAuthenticator props />;
  };
};

编译错误:

>>>> Start compiling
[1/3] Building src/aws/AuthenticatorBS-ReactHooksTemplate.cmj

  We've found a bug for you!
  /Users/prisc_000/working/DEMOS/my-app/src/aws/AuthenticatorBS.re 34:6-25

  32 │   [@react.component]
  33 │   let make = () => {
  34 │     <AppWithAuthenticator props />;
  35 │   };
  36 │ };

  This call is missing an argument of type props

【问题讨论】:

  • withAuthenticator 是一个高阶组件构造函数。应用于组件时返回另一个组件的函数。不能直接使用。
  • 谢谢你,@glennsl。你能指出一个绑定到 HOC 的资源/示例吗?
  • 我不能,因为我什么都没看到。不过,我确信某个地方存在,因为使用新 API 似乎并不那么难。如果您到那时还没有弄清楚,我明天也许可以进一步研究它。
  • 谢谢您,先生。如果我想出任何东西会更新。现在看一些帖子。

标签: interop aws-amplify higher-order-components reason reason-react


【解决方案1】:

按照这些思路应该可以工作:

[@genType.import ("aws-amplify-react", "withAuthenticator")]
external withAuthenticator : (React.component('a), bool) => React.component('a) = "withAuthenticator";

module AppWithAuthenticator = {
  [@bs.obj]
  external makeProps: (~children: 'children=?, unit) => {. "children": 'children } = "";
  let make = withAuthenticator(App.make, true);
};

ReactDOMRe.renderToElementWithId(<AppWithAuthenticator />, "root");

external withAuthenticator : ... 将外部 HOC 构造函数声明为一个函数,该函数接受一个 react 组件和一个 bool,并返回一个组件,该组件将接受完全相同的 props,因为两个位置都使用了 'a 类型变量。

module AppWithAuthenticator ... 将 HOC 构造函数应用于 App 组件并对其进行设置,以便它可以与 JSX 一起使用。这和直接导入react组件基本一样,只是我们通过函数调用的方式获取外部组件,而不是直接导入。

最后,最后一行只是演示了如何使用它。

请注意,我显然没有正确测试过这个,因为我没有使用aws-amplify 等设置项目。我也从未使用过genType,但对于这个用例来说似乎很简单。

【讨论】:

  • 当你说它需要完全相同的道具时,bool 在这个例子中是道具吗?右侧的 'a 是否期望作为 'a 或 'a 和 bool 传递的内容?
  • 不,这是一个普通的函数参数。 props 由'a 表示,预计是某种 js 对象类型。不幸的是,在 Reason 中无法扩展对象类型,但如果需要,您可以对输入和输出 props 进行硬编码。
  • 我认为 bs.modulegenType.import 不应该有所作为。但是你的withAuthenticator 绑定很破旧。首先,它需要将一个组件作为第一个参数,否则它根本就不是 HOC。然后,正如我从文档中了解到的那样,您可以提供一个选项对象而不是 bool 参数,我认为这是您想要做的。但是从文档中我看不到任何 Comp 选项。但是有一个authenticatorComponents 选项。
  • 最后,options 对象与 props 对象不同。这些需要分开。
  • Comp 有要包装的组件,作为第一个参数传递。它不是选项对象的有效属性。
【解决方案2】:

原因不和谐频道再次罢工。此解决方案有效:

[@bs.module "aws-amplify-react"]
external withAuthenticator:
  // takes a react component and returns a react component with the same signature
  React.component('props) => React.component('props) =
  "withAuthenticator";

module App = {
  [@react.component]
  let make = (~message) => <div> message->React.string </div>;
};

module WrappedApp = {
  include App;
  let make = withAuthenticator(make);
};

如果你想传递第二个includeGreeting 属性,就像@glennsl 的回答一样:

[@bs.module "aws-amplify-react"]
external withAuthenticator:
  // takes a react component and returns a react component with the same signature
  (React.component('props), bool) => React.component('props) =
  "withAuthenticator";

module App = {
  [@react.component]
  let make = (~message) => <div> message->React.string </div>;
};

module WrappedApp = {
  include App;
  let make = withAuthenticator(make,true);
};

你可以这样称呼它:

ReactDOMRe.renderToElementWithId(<WrappedApp message="Thanks" />, "root");

感谢@bloodyowl。

如果你不使用include,这就是它的样子。请参阅下面的@glennsl 评论。

module WrappedApp = {
  let makeProps = App.makeProps;
  let make = withAuthenticator(App.make,true);
};

【讨论】:

  • 嗯,巧妙地使用include App 来“继承”makeProps。但除此之外并使用bs.module 而不是genType.import,还有其他区别吗?解决方案似乎基本相同。
  • 我没有资格回答这个问题,兄弟。导入方法无关紧要。唯一的区别可能是一种解决方案足够简单,我可以理解。我很想知道您的解决方案将如何工作。使用您的方法,@bloodyOwl 的答案会是什么样子?我无法让它工作。我很乐意在此处添加您的答案:dev.to/idkjs/…
  • 基本上是一样的,除了include App;你会手动定义let makeProps,就好像你从js导入组件一样。或者如果WrappedApp 应该具有与App 完全相同的道具,您也可以将makeProps 别名为App: let makeProps = App.makeProps;。这正是include App; 所做的,除了它 包括App 中的所有其他内容。
  • 我可能会在这里针对 HOC 进行单独的问答,以更一般地解释它,并避免与 amplify-aws 之类的所有噪音。
  • Here 是。如果还有什么不清楚的地方请告诉我。
猜你喜欢
  • 1970-01-01
  • 2019-05-16
  • 2020-05-10
  • 2019-06-09
  • 1970-01-01
  • 2018-09-01
  • 2019-04-08
  • 1970-01-01
  • 2017-10-18
相关资源
最近更新 更多