Creating a DatePicker from CDN with React API

1.3k views Asked by At

I am importing some React modules from CDN (that's not a requirement, I've also tried with a local build, more in the final question about it):

<script crossorigin src="https://unpkg.com/[email protected]/dist/react-onclickoutside.min.js"></script>
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.0/moment.min.js" integrity="sha512-Izh34nqeeR7/nwthfeE0SI3c8uhFSnqxV0sI9TvTcXiFJkMd6fB644O64BRq2P/LA/+7eRvCw4GmLsXksyTHBg==" crossorigin="anonymous"></script>
<script crossorigin src="https://unpkg.com/[email protected]/dist/react-datepicker.min.js"></script>

Then I have a script to build the React DatePicker component, this is the relevant snippet from it:

 HelloWorld.Example=function()
 {
  var p,setCount,count,p$1,c,myDate,datePicker;
  p=React$2.useState(0);
  setCount=p[1];
  count=p[0];
  p$1=React$2.useState(new moment(new Date((c=Date.now(),DateUtil.DatePortion(c)))));
  myDate=p$1[0];
  datePicker=React$2.createElement(DatePicker.default,{
   selected:new moment(new Date()),
   onChange:p$1[1]
  });
  React.set_setCount(setCount);
  return React$2.createElement("div",null,datePicker,React$2.createElement("p",null,(Html.textf(function($1)
  {

The error that I see from the JS Console is:

react-datepicker.min.js:1 Uncaught TypeError: o is not a function
    at Ee (react-datepicker.min.js:1)

when the script call ReactDOM.render.

Is there a way to understand what is o ? Maybe an import missing? (Edit Well, looking at chrome debugger and comparing it to github, o is isValidDate, i.e. import isValidDate from "date-fns/isValid";, hence the imports from date-fns are not working from CDN )

Is there a way such that - for example - I can locally npm run build the needed module, react-datepicker, and then call the react API from my script as shown above? (a suggestion that I received was configuring my script as entry in webpack, but afaik React doesn't use webpack, though I see it is used in react-datepicker).

From React docs, I can read that

JSX is not a requirement for using React

so something like the above should be doable, in theory.

I've opened a question/issue on github react-datepicker repo (in the context of calling this component from WebSharper.React).

2

There are 2 answers

0
AudioBubble On BEST ANSWER

Is there a way such that - for example - I can locally npm run build the needed module, react-datepicker, and then call the react API from my script as shown above?

Yes, there is a well known solution!

Write an index.js as follows

import React from "react";
import DatePicker from 'react-datepicker'
import "react-datepicker/dist/react-datepicker.css";

export {ImportedComponent}

window.MyDatePicker = function MyDatePicker(props) {
    console.log("props from window.MyDatePicker", props)
    return React.createElement( DatePicker, props );
  }

build via npm and copy the static folder from the build of your by npm run build to the SPA folder of your proj

copy the 3 script tags from the index.html in the build into the index.html template of your proj and <div id="root"></div> (of course you use a different id for your project app and there will be nothing to render here)

in my case they are (they will be different for you)

<div id="root"></div>
<script>!function(e){function t(t){for(var n,l,p=t[0],f=t[1],i=t[2],c=0,s=[];c<p.length;c++)l=p[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(a&&a(t);s.length;)s.shift()();return u.push.apply(u,i||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,p=1;p<r.length;p++){var f=r[p];0!==o[f]&&(n=!1)}n&&(u.splice(t--,1),e=l(l.s=r[0]))}return e}var n={},o={1:0},u=[];function l(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,l),r.l=!0,r.exports}l.m=e,l.c=n,l.d=function(e,t,r){l.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,t){if(1&t&&(e=l(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(l.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)l.d(r,n,function(t){return e[t]}.bind(null,n));return r},l.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(t,"a",t),t},l.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},l.p="/";var p=this.webpackJsonpcontent_npm=this.webpackJsonpcontent_npm||[],f=p.push.bind(p);p.push=t,p=p.slice();for(var i=0;i<p.length;i++)t(p[i]);var a=f;r()}([])</script>
<script src="/static/js/2.a6e4c224.chunk.js"></script>
<script src="/static/js/main.b075c560.chunk.js"></script>

Now go with

datePicker=React$1.createElement(window.MyDatePicker,{
   selected:myDate,
   onChange:p$1[1],
   showTimeSelect: true,
  });

in you SPA.js and enjoy any react component like this one from WebSharper.React!

Btw I had to pass a JS date, not a Moment date here in the selected of props, I'm not sure why, anyway, this is not relevant to the problem.

FYI, this is the F# code from WebSharper project

let myDate, setMyDate = WrapReact.UseState (DateTime.Today.JS)
let importDatePicker = JS.Eval("window.MyDatePicker") :?> React.Class 
let propDP = 
                {
                    selected = myDate 
                    onChange = setMyDate
                    showTimeSelect = true
                }
let datePicker =
    React.CreateElement( importDatePicker, propDP)
WrapReact.setCount <- setCount
div [] [
    
    datePicker
    p [] [Html.textf "You selected %s date %s time" (myDate.ToDateString()) (myDate.ToTimeString())]

Full open source project shared on github.

0
AudioBubble On

I think that the main problem is that WebSharper scripts are not JavaScript modules. In that case it should be immediate to import an external module or make the above SPA.js as the Webpack main entry. In fact it is well known that there are differences between <script type=module> and <script>

  • Module Script Execute in Strict Mode
  • Module Script has its Own Scope
  • Module Script can Import other Javascript Modules
  • Module Script has this as Undefined
  • Inline Module Script can have async Attribute
  • Module Script is Always Deferred

As confirmed by Adam Granicz indeed on WebSharper side:

that should be the way, yes, @Jand42 and others have been working on changing the current output to support modules and a better TS interoperability - this has been on the agenda for years, so closing it would be a good step forward

(In the meantime there are of course alternatives, e.g. flatpickr, which has bindings also for jQuery, instead of react-datepicker or pure React or F# Fable instead of WebSharper.React and so on)