so im trying to create a react webcomponent. I wrap it and on VSCode looks fine, but when I'm trying to load it, it gives me the error: Unexpected token '<' on the line:
ReactDOM.render(<Counter/>, mountPoint);
Does anyone know why and how to fix it? thanks
This is my WebComponent:
import React from 'react';
import * as ReactDOM from 'react-dom';
import Counter from './counter';
class CounterWC extends HTMLElement {
connectedCallback() {
// Create a ShadowDOM
const root = this.attachShadow({ mode: 'open' });
// Create a mount element
const mountPoint = document.createElement('div');
root.appendChild(mountPoint);
// You can directly use shadow root as a mount point
ReactDOM.render(<Counter/>, mountPoint);
}
}
customElements.define('counter-wc', CounterWC)
And this is my html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-9" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>React webcomponent:</h1>
<counter-wc></counter-wc>
<script type="module" src="./counterWC.js"></script>
</body>
</html>
Re: comments
The fact that you name your file *.js doesn't mean it is JavaScript
ReactDOM.render(<Counter/>, mountPoint); is JSX, not JavaScript, it needs to be converted in a Build step to JavaScript.
Or do not use React at all:
class CounterWC extends HTMLElement {
constructor(){
super()
.attachShadow({mode: 'open'})
.append(this.div = document.createElement('div'));
}
connectedCallback() {
this.div.innerHTML = `Am I a counter?`;
}
}
customElements.define('counter-wc', CounterWC);
<counter-wc></counter-wc>
Related
I want to use web components, but I don't want to write all the contents in the same file. How to implement it? person-panel in index.html has been added in the server,not js.
file structure
/index.html
/index.js
/PersonPanel/personPanel.js
/PersonPanel/template.html
index.html
<html>
<head>
<script src="index.js" type="module" />
</head>
<body>
<person-panel></person-panel>
</body>
</html>
index.js
import personPanel from './PersonPanel/personPanel.js';
// other operations that may require a PersonPanel
template.html
<template>
<label class="field"></label>
</template>
personPanel.js
class PersonPanel extends HTMLElement {
constructor() {
super();
this.attachShadow({mode : 'open'});
// how to fetch template?
}
static get observedAttributes() {
return ['field'];
}
attributeChangedCallback(name, oldValue, newValue) {
if(name == 'field'){
this.shadowRoot.querySelector('label.field').innerText = newValue;
}
}
}
window.customElements.define('person-panel', PersonPanel);
export default PersonPanel;
import abcjs from 'abcjs';
export default class MusicScore extends Component {
constructor(props) {
super(props);
this.state={
data: this.props.navigation.getParam('abctune'),
}
}
render(){
data = this.state.data;
renderScore = () => {
abcjs.renderAbc('notation', data);
}
return(
<WebView
source={
{html: `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="notation"></div>
</body>
</html>
`}
}
domStorageEnabled
javaScriptEnabled
injectJavaScript={renderScore}
/>
);
}
}
The code above produces the following
OUTPUT
dev enviornment:
OS: Windows 10
node: v12.10.0
Android Studio: 3.5.2
installed via package manager:
npm install --save abcjs
Unfortunately, you need a DOM set up. I haven't used react-native, so I'm not sure if this will work:
What works for me when using a SSR package (like Nuxt) is to change the import to later in the process. So:
mounted() {
const abcjs = require('abcjs');
}
Is there something analogous in react-native?
I have an React App, following is JavaScript code
import React from 'react';
import ReactDOM from 'react-dom';
const App = function(){
return <div>Hi</div>
}
ReactDOM.render(<App />, document.querySelector('.container'));
And the HTML file is as following.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/style/style.css">
<link rel="stylesheet" href="https://cdn.rawgit.com/twbs/bootstrap/48938155eb24b4ccdde09426066869504c6dab3c/dist/css/bootstrap.min.css">
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAq06l5RUVfib62IYRQacLc-KAy0XIWAVs"></script>
</head>
<body>
<div class="container"></div>
</body>
<script src="/bundle.js"></script>
</html>
The question I don't understand is that if I remove import React from 'react', it will show error message like below.
Uncaught ReferenceError: React is not defined
But I don't use React in my code explicitly anywhere, why would it show a message like this. Can anyone tell me what's going on under the hood?
UPDATE:
Not exactly the same question with this one, since what I have in my code is just an individual component, not involving any parent component.
Using JSX (<App />) is just a syntatic sugar for React.createElement().
So when your code is transpiled to pure javascript, references to React will appear there, so you need the import for that.
So yes, you're using it, although you don't see it
See what is your code transpiled to here
'use strict';
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var App = function App() {
return React.createElement(
'div',
null,
'Hi'
);
};
_reactDom2.default.render(React.createElement(App, null), document.querySelector('.container'));
I'm struggling to get #Method in stenciljs working - any help would be appreciated.
Here's my component code with a function called setName that I want to expose on my component:
import { Component, Prop, Method, State } from "#stencil/core";
#Component({
tag: "my-name",
shadow: true
})
export class MyComponent {
#Prop() first: string;
#Prop() last: string;
#State() dummy: string;
#Method() setName(first: string, last: string): void {
this.first = first;
this.last = last;
this.dummy = first + last;
}
render(): JSX.Element {
return (
<div>
Hello, World! I'm {this.first} {this.last}
</div>
);
}
}
Here's the html and script that references the component:
<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0">
<title>Stencil Component Starter</title>
<script src="/build/mycomponent.js"></script>
</head>
<body>
<my-name />
<script>
var myName = document.querySelector("my-name");
myName.setName('Bob', 'Smith');
</script>
</body>
</html>
Here's a screen shot of the error I'm getting which is Uncaught TypeError: myName.setName is not a function:
Methods are not immediately available on a component; they have to be loaded/hydrated by Stencil before you can use them.
Components have a componentOnReady function that resolve when the component is ready to be used. So something like:
var myName = document.querySelector("my-name");
myName.componentOnReady().then(() => {
myName.setName('Bob', 'Smith');
});
Just posting another answer because this has since changed, with Stencil One.
All #Method decorated methods are now immediately available on the component, but they are required to be async, so that you can immediately call them (and they resolve once the component is ready). The use of componentOnReady for this is now obsolete.
However, you should make sure that the component is already defined in the custom element registry, using the whenDefined method of the custom element registry.
<script>
(async () => {
await customElements.whenDefined('my-name');
// the component is registered now, so its methods are immediately available
const myComp = document.querySelector('my-name');
if (myComp) {
await myComp.setName('Bob', 'Smith');
}
})();
</script>
Here you should not use #Method , it is not a best practice. We should always minimize the usage of #Method. This helps us to scale the app easily.
Instead pass data through #Prop and #Watch for it.
Ok , in your case , Please add async before the method name
I am using global script declaration inside index.html
<!DOCTYPE html>
<html>
<head>
<script src='https://js.espago.com/espago-1.1.js' type='text/javascript'></script>
...
</head>
<body>
...
</body>
Now I want to use it inside the component.
import * as React from "react";
import * as $ from "jquery";
//how to import Espago?
export default class EspagoPayment extends React.Component<any, any> {
componentDidMount() {
$("#espago_form").submit(function(event){
var espago = new Espago({public_key: 'xxx', custom: true, live: false, api_version: '3'});
espago.create_token({
...
});
});
}
render() {
return (
...
);
}
}
Webpack gives an error on build.
error TS2304: Cannot find name 'Espago'
How to get Espago visible inside the component?
Maybe there is other way to link to online js resource?
You have to tell TypeScript that it's defined somewhere else.
declare var Espago: any;
See https://stackoverflow.com/a/13252853/227299