Decorator feature not working (unexpected token) - javascript

Just tried to use decorators in React:
import React from 'react';
import Fade from './Transitions/Fade'
import withVisible from './withVisible'
#withVisible()
const App = props =>
<Fade visible={props.visible} duration={500}>
Hello
</Fade>
export default App
If I use the common way ( withVisible()(App) ) then it's working properly.
(My guess is that NodeJS can't compile my code with the # ) [Syntax error: Unexpected token (#) ]
import React from 'react'
const withVisible = () => Component =>
class WithVisible extends React.Component {
state = {
visible: true
}
render() {
return (
<Component visible={this.state.visible} {...this.props}/>
)
}
}
export default withVisible

Probably your .babelrc do not have added decorator plugin.
Try this: https://babeljs.io/docs/plugins/transform-decorators

You need transform-decorators-legacy babel plugin to make this syntax work.

Related

Ace: Create a custom mode in NextJS

I am trying to use ace to create an sql editor, but I need a unique highlight. So, I need to create a custom mode that inherits from the existing sql mode.
The issue is, because ace uses window, and nextjs is ssr, I am unable to create a custom mode using ace's tutorials as I get the window is not defined error in the .ts file.
I can get around this error in the .tsx file by importing it with next/dynamic and disabling ssr for that component, but for the mode I am stumped.
SqlMode.js (it's not .ts because ace typing just doesn't work for me)
import ace from 'ace-builds/src-noconflict/ace';
import 'ace-builds/src-noconflict/mode-sql'
export class SqlHighlightRules extends window.ace.acequire('ace/mode/text_highlight_rules').TextHighlightRules {
constructor() {
super();
this.$rules.start.unshift({
token: 'text-orange-main',
regex: '{{*.}}',
})
}
}
export class SqlMode extends window.ace.acequire('ace/mode/sql').Mode {
constructor() {
super()
this.HighlightRules = SqlHighlightRules;
}
}
The compilation fails in this file, as it uses window, which is undefined.
Editor.tsx
import { useEffect, useRef, useState } from 'react';
import AceEditor from 'react-ace';
import 'ace-builds/src-noconflict/ace';
import 'ace-builds/src-noconflict/theme-tomorrow';
import { SqlMode } from './config/SqlMode';
import 'ace-builds/src-noconflict/ext-language_tools';
const styles = { borderRadius: 8 };
export default function Editor() {
const editor = useRef<AceEditor>();
const [code, setCode] = useState<string>('');
useEffect(() => {
const mode = new SqlMode();
//#ts-ignore
editor.current.editor.getSession().setMode(mode);
}, []);
return (
<AceEditor
ref={editor}
theme="tomorrow"
value={code}
onChange={setCode}
enableBasicAutocompletion
enableLiveAutocompletion
style={styles}
/>
);
}
This file works if used through next/dynamic with { ssr: false } and without the custom mode. But as soon as I use the custom mode, errors.
sql.page.tsx
import dynamic from 'next/dynamic';
const Editor = dynamic(() => import('../components/editor/Editor'), { ssr: false });
export default function SqlEditor() {
return (
<div className="w-full h-full flex justify-center items-center">
<Editor />
</div>
);
}
I would like to be able to create a custom highlight for the sql mode, while working with nextjs. If there is a solution I am not aware of, I'd be happy to learn.
Alternatively if there is another FE editor I could use that does largely the same thing as ace, that could also be useful.
Thank you.

Is there a way to import a function using Next.js dynamic import? react-component-export-image issues with Next.js ssr

I was getting the 'window is not defined' error when importing react-component-export-image so I used a dynamic import to get around that. I don't get that error anymore but now I get 'exportComponentAsPNG(componentRef) is not a function'. Is there a better way to deal with the 'window is not defined' error or a way to use the function I am importing dynamically? If not, is there a different npm library that works to generate an image from a react component?
import React, { useRef } from 'react'
// import { exportComponentAsPNG } from 'react-component-export-image' *This gave window not defined error so I used dynamic import*
import dynamic from 'next/dynamic'
import ProductCard from '../ProductCard/ProductCard.component'
import Button from '../Button/Button.component'
const { exportComponentAsPNG } = dynamic(
() => import('react-component-export-image'),
{
ssr: false
}
)
const Plaque = () => {
const componentRef = useRef()
// eslint-disable-next-line react/display-name
const ComponentToPrint = React.forwardRef((props, ref) => {
return (
<div ref={ref}>
<ProductCard />
</div>
)
})
return (
<ComponentToPrint ref={componentRef} />
<button onClick={() => exportComponentAsPNG(componentRef)}> // "Error: exportComponentAsPNG is not a function"
Export As PNG
</button>
)
}
export default Plaque
next/dynamic is used to dynamically import React components, not regular JavaScript functions or libraries.
For that, you can use a regular dynamic import on exportComponentAsPNG inside the onClick callback.
<button onClick={async () => {
const { exportComponentAsPNG } = await import('react-component-export-image')
exportComponentAsPNG(componentRef)
}}>
The exportComponentAsPNG function needs access to window which is undefined with server side rendering. I was able to fix the issue by dynamically importing the Plaque component that used exportComponentAsPNG to the page where it is called with sever side rendering set to 'false'.
import dynamic from 'next/dynamic'
const Plaque = dynamic(() => import('../compnonents/Plaque'), {
ssr: false
})
const Page = () => {
return <Plaque />
}
export default Page
Now that the component is no longer using SSR I was able to import and use the function normally.
import { exportComponentAsPNG } from 'react-component-export-image'
Here you can find the documentation for the library: https://www.npmjs.com/package/react-component-export-image

Use imported function in return method (invalid hook call, react js)

Wassup Guys,
I have a reusable component, that translates keys into a choosen language through keynames as string or a binded var.
Usually I use a tag for this, but because of different reasons I am switching/replacing current translations with {t('...')}.
Here is the code of the component:
import React from 'react';
import { useTranslation as defaultTranslation } from 'react-i18next';
import i18next from 'i18next';
export const useTranslation = (ns = 'common', options) => {
return defaultTranslation(ns, {
useSuspense: false,
...options,
});
};
export const withTranslation = (Component, ns, options) => {
const TranslatedHOC = (props) => {
const translationProps = useTranslation(ns, options);
return <Component {...translationProps} {...props} />;
};
return TranslatedHOC;
};
export const getCurrentLanguage = () =>
i18next.language || localStorage.getItem('language') || 'de-DE';
First of all I define the const for the used imported function:
const {t} = useTranslation();
normal case: importing my component in the file, where I want to use it and add code above.
Code of my component, where I want to replace the Tags.
// Import React Table
import ReactTable from 'react-table';
import 'react-table/react-table.css';
import LocalizedText from '#components/i18n/LocalizedText';
class T extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
pages: null,
loading: true,
};
this.fetchData = this.fetchData.bind(this);
}
fetchData(state, instance) {
this.props.onFetchData(state, instance).then(() => {
this.setState({
loading: false,
});
});
}
render() {
return (
<ReactTable
{...this.props}
previousText={
<LocalizedText textKey="caseoverview.orderproduct.back" />
}
nextText={
<LocalizedText textKey="caseoverview.orderproduct.continue" />
}
loadingText={<LocalizedText textKey="loading" />}
noDataText={<LocalizedText textKey="placeholders.nodata" />}
pageText={
<LocalizedText textKey="reservationcalculator.search.result.page" />
}
ofText={<LocalizedText textKey="from" />}
rowsText={<LocalizedText textKey="rows" />}
className="case-search-table"
/>
);
}
}
export default T;
...
previousText={
<LocalizedText textKey="caseoverview.orderproduct.back" />
}
...
should change to:
...
previousText={
t('caseoverview.orderproduct.back')
}
...
The problem is, that I can't use the code quoted above without getting any issues regarding invalid hook calls. If I move it out somehow, I get errors telling me that my 't' is either not defined or an unexpected token. Could someone help me out? Searched online for solutios without any result.
A hook can only be used in a functional component. You can change this class component to a functional component, or you can use react-i18next's withTranslation HOC to wrap your class component. See https://react.i18next.com/latest/withtranslation-hoc#when-to-use
#kevin asworth answer helped me out.
Using withTranslation with passing t as prop
const {t} = this.props;
inside the render method worked for me.

Uncaught Error: Cannot Find Module When Using Dynamic Import for JavaScript

I'm using Create-React-App and am looking to use the dynamic import() supported by webpack 2.0 to import a module based on a variable string.
I've looked at the official proposal (https://github.com/tc39/proposal-dynamic-import) and it seems possible to do something like this:
import(`./language-packs/${navigator.language}.js`)
But it breaks when I try something similar.
AppRoutes.js
import LazyLoad from 'services/LazyLoad';
export class AppRoutes extends React.Component {
render() {
return (
<Switch>
<Route
exact path="/"
render={(matchProps) => (
<LazyLoad
absoluteModulePath='pages/default/HomePage'
getComponent={() => import('pages/default/HomePage')}
{...matchProps}
/>
)}
/>
</Switch>
);
}
}
export default AppRoutes;
pages/default/HomePage/index.js
import React from 'react';
export const HomePage = () => {
return (
<div>
I'm the default HomePage
</div>
);
}
export default HomePage;
BROKEN services/LazyLoad/index.js
import React from 'react';
export class LazyLoad extends React.Component {
...
componentDidMount() {
import(this.props.absoluteModulePath) // Critical dependency: the request of a dependency is an expression
.then(module => module.default)
.then(AsyncModule => this.setState({AsyncModule}))
}
...
}
export default LazyLoad;
Error:
But when I change the LazyLoader to
WORKING services/LazyLoad/index.js
import React from 'react';
export class LazyLoad extends React.Component {
...
componentDidMount() {
this.props.getComponent()
.then(module => module.default)
.then(AsyncModule => this.setState({AsyncModule}))
}
...
}
export default LazyLoad;
it works.
The absolute paths is something built into create-react-app with the help of environment variables.
.env
NODE_PATH=src/
I require dynamically loading modules this way to build a proof of concept for multi-tenancy. How can I fix the broken LazyLoad such that I can pass a string as a prop and have the LazyLoad component dynamically load the component from that string prop?
Only partially dynamic statement are allowed for import().
In your AppRoutes.js you could do this:
...
<LazyLoad
modulePath='HomePage'
getComponent={() => import('pages/default/HomePage')}
{...matchProps}
/>
then in your LazyLoad Component you do:
componentDidMount() {
import(`pages/default/${this.props.modulePath}/index.js`)
.then(module => module.default)
.then(AsyncModule => this.setState({AsyncModule}))
}
Fully dynamic statements, such as import(foo), will fail because webpack requires at least some file location information.The import() must contain at least some information about where the module is located, so bundling can be limited to a specific directory or set of files.
https://webpack.js.org/api/module-methods/#import-

Exporting functions with reactjs and babel

I have a project using reactjs, which is transpiled by babel. I use the es2015 and react transforms in my .babelrc. I am currently refactoring and in my first pass I basically did export class foo for everything I needed. A lot of these classes should really just be functions, so I am trying to rewrite them as such, but I keep getting the same error. My main application file looks somethings like this:
import React, { Component } from 'react';
import {Foo, Bar} from './components/ui.js';
class Application extends Component {
constructor(props){
super(props);
this.state = {
object: null
}
}
componentDidMount(){
// code
}
componentDidUpdate(){
// other code
}
render(){
return(
<div>
<Foo />
<Bar />
</div>
)
}
}
module.exports = Application
And my import from ui.js is like this:
import React, { Component } from 'react';
export class Foo extends Component {
constructor(props){
super(props);
}
render() {
return (
// Some JSX
)
}
}
export class Bar extends Component {
constructor(props){
super(props);
}
render() {
return (
// Some other JSX
)
}
}
When I try and change one of these exported classes to a function, for example:
// Note: I have tried a variety of syntax such as function, const, etc...
export var Bar {
render() {
return (
// Some other JSX
)
}
}
I get the following error:
SyntaxError: Unexpected token <line where I declare a function>
I am not sure what I am doing wrong, and my google searches are only coming up with answers to other problems.
It's the same as defining the function as a variable but just adding export to the front e.g. (using ES6 syntax)
export const render = () => (
// Some other JSX
);
or alternatively
export var render = function() {
return (
// Some other JSX
);
};
Exporting functions is no different than exporting class. Basic rules must be followed .
Function/Class name should in CAPS
There will be only one "export" line .
Every function return body should have a single tag encompassing other parts. Most commonly used is a tag .
This usually works: import App from "./App"; where App.js is my jsx file.
You can do an explicit import too . : import AllApp from "./classhouse.jsx";
Name of the js/jsx file does not matter. It can be anycase (lower, upper).
For returning multiple functions from one file, you need to create one more function , that encompasses all other functions .
See the example below showing multiple functions returned.
import React from 'react';
/* All function / class names HAS TO BE in CAPS */
var App1 = function (){
return (
<div>
<h1>
Hello World
</h1>
</div>
)
}
var App2 = function (){
return (
<div>
<h1>World Number 2 </h1>
</div>
);
}
var AllApp = function (){
return (
<div>
<App1 />
<App2 />
</div>
);
}
export default AllApp;
My index.js file:
import React from 'react';
import ReactDOM from "react-dom";
import AllApp from "./classhouse.jsx"; /* Note: App name has to be in CAPS */
import App from "./App";
const jsx =
<div>
<AllApp />
<App />
</div>
ReactDOM.render(jsx, document.getElementById("root"));
You are writing functional components in wrong way.
function Welcome() {
return <h1>Hello World</h1>;
}
or
const Welcome = () => {
return <p>Hello Wrold</p>
}
export default Welcome ;
ES6 doesn't allow export default const. You must declare the constant first then export it.

Categories

Resources