Unexpected Token after const - meteor

I am getting an unexpected token error in React when I try to specify a constant, and I cannot seem to figure out why.
My code is pretty simple, and I have followed the react-bootstrap examples here almost exactly.
My code is as follows:
import { Component, PropTypes } from 'react';
var rbs = require('react-bootstrap'),
Panel = rbs.Panel;
export default class ResumeSection extends Component {
constructor(...args) {
super(...args);
this.state = {
open: true
};
}
const title = (
<h3>Panel title</h3>
);
render() {
return (
<Panel collapsible expanded={this.state.open}>
<p>Body</p>
</Panel>
);
}
}
The error occurs on title directly after const and just says SyntaxError: Unexpected Token

You can't define a const in the class body like that; it should be moved into a method.
render() {
const title = (
<h3>Panel title</h3>
);
// ...
}

Apparently, this is called "Public Class Field Syntax" and is already available in babel as the plugin, babel-plugin-transform-class-properties. I have not tried it as yet though.
Additional reference is reactjs.org events guide

Related

Can I implement typescript conditional types by javascript object values

I am writing a React editor component, it could be used to write new posts or update an existing post.If used as an update editor, the props MUST receive title and content; if used as new post editor, title and content will not exist.
But I don't know how to let typescript access the "flag" props so that it could decide which interface it could use.
I want to use the component as follows:
<PostEditor flag="newPost"/>
<PostEditor
flag="updatePost"
title="a good story"
content="once upone a time"
/>
I write the interface as follows:
interface NewPostProps{
flag:"newPost",
}
interface UpdatePostProps{
flag:"updatePost",
title:string,
content:string,
}
type IPostEditorProps<T>= T extends "newPost"?NewPostProps:UpdatePostProps
I write the react component as this. It does not work. I want the flag props to be the generic type but I don't know how to write that.
export const PostEditor=({flag,title}:IPostEditorProps<T>)=>{
// component contents
return (<></>)
}
Thank you for your help.
Working example code:
interface CommonProps {
children?: React.ReactNode;
// ...other props that always exist
}
interface NewPostProps {
content: never;
flag: "newPost";
title: never;
}
interface UpdatePostProps {
content: string;
flag: "updatePost";
title: string;
}
type ConditionalProps = NewPostProps | UpdatePostProps;
type Props = CommonProps & ConditionalProps;
export const PostEditor = (props: Props): JSX.Element => {
const { children, content, flag, title } = props;
if (flag === "newPost") return <>{/* implement newpost */}</>;
return (
<div>
<h1>{title}</h1>
<p>{content}</p>
{children}
</div>
);
};
Useful link: conditional react props with typescript
If you have any questions, feel free to ask!

Next.js hydration error using Keycloak SSR package

I am using #react-keycloak/ssr with latest next.js, just started so project as clean as possible, all I really have are installed dependencies and _app.tsx with index.tsx from examples.
_app.tsx is identical copy (except url to keycloak) of official github example and index.tsx is next:
import { useKeycloak } from '#react-keycloak/ssr'
import {KeycloakInstance, KeycloakTokenParsed} from 'keycloak-js'
type ParsedToken = KeycloakTokenParsed & {
email?: string
username?: string
}
export default function Index() {
const { keycloak } = useKeycloak<KeycloakInstance>()
const parsedToken: ParsedToken | undefined = keycloak?.tokenParsed
const state = keycloak?.authenticated ? <span>{parsedToken?.username}</span> : <span>'Undefined'</span>;
function handleLoginButtonClick() {
if (keycloak) {
window.location.href = keycloak.createLoginUrl()
}
}
return (
<div>
{state}
<button className="btn btn-blue" onClick={() => handleLoginButtonClick()}>Login</button>
</div>
)
}
And my problem is that after a login I am getting errors
Warning: Text content did not match. Server: "" Client: "'Undefined'"
at span
at div
at Index (webpack-internal:///./pages/index.tsx:18:84)
I've tried to implement state change using useEffect but then keycloak?.authenticated is always false,
let [state] = useState('No user');
useEffect(() => {
state = keycloak?.authenticated ? 'User' : 'No user';
}, []);
then I tried to use getServerSideProps, but then I get an error that useKeycloak hook can be used inside a function only.
What else can I try?
p.s. Short gif/video of what is happening https://imgur.com/a/c2q6ftU
Found a solution by tweaking useEffect slightly:
const [username, setUsername] = useState('unknown')
useEffect(() => {
if (keycloak?.authenticated) {
setUsername(parsedToken?.email)
}
}, [keycloak?.authenticated])

How to write constructor to set state and change state in next js

Hi I am building one next js app
I have build component components/search_location.js
constructor(props) {
super(props);
this.state = {locations: props.locations};
}
export default function SearchLocation({locations}){
return(
<div>
<h1></h1>
</div>
)
}
But with above code I am getting error saying
SyntaxError: /Users/search_project/components/search-location.js: Unexpected token, expected ";" (4:17)
export default function SearchLocation({locations}){
constructor(){
^
this.state = {
data: 'www.javatpoint.com'
}
I want to set state and then onclick of some button I want to change state as well, Can someone please suggest me how to do this?
You have a syntax error, constructor is something that is available only in javascript classes.
You should change your exported component from functional component to class component.
It should looks like this:
import React from 'react';
export default class extends React.Component {
constructor() {
this.state = {
data: 'www.javatpoint.com',
};
}
render() {
return <div>Content here</div>;
}
}

Reactjs custom hook call infinite loop

I am creating my first ever self made web development project and have run into an infinite loop. The full project can be found on https://github.com/Olks95/my-dnd/tree/spellbook. So the question is: What causes the loop and how do I fix it?
(The loop happens somewhere in the 2nd item of the 'Playground' component when the ContentSelector - Spellbook is called. The custom hook useHandbook is called in Spellbook and continously calls the API, should obviously only happen once... refresh or click return to stop spamming )
From what I can tell the issue is not in the custom hook itself, as I have made several attempts to rewrite it and an empty dependency array is added to the end of the useEffect(). I will try to explain with example code here.
import { Component1, Component2, Component3 } from './ContentSelector.js';
const components = {
option1: Component1,
option2: Component2
option3: Component3
}
const Playground = (props) => {
const LeftItem = components['option1']
const MiddleItem = components['option2']
const RightItem = components['option3']
...
}
I wanted to be able to choose what content to put in each element and ended up making a ContentSelector component that has all the content components in one file, and individually imported/exported. This seems like a strange way to do it, but it was the only way I found to make it work. (Maybe the cause of the loop?) Since this is still fairly early on in the development the selection is hard coded. The item variables starts with a capital letter so I can later call them as components to render like so:
<LeftItem ...some properties... />
Playground then returns the following to be rendered:
return(
<React.Fragment>
<div className="container">
<div className="flex-item">
/* Working select-option to pass correct props to Component1 */
<div className="content">
<LeftItem ...some properties... />
</div>
</div
<div className="flex-item">
/* Currently the same selector that changes the content of the LeftItem */
<div className="content">
<MiddleItem ...some properties... />
</div>
</div>
/*RightItem follows the same formula but currently only renders "coming soon..." */
</div>
</React.Fragment>
)
The Content selector then has the three components where:
Component1: calls a custom hook that only runs once. The information is then sent to another component to render. All working fine.
Component2: calls a custom hook infinite times, but is expected to work the same way component 1 does...
Component3: Renders coming soon...
See Component1 and 2 below:
export const Component1 = (props) => {
const [ isLoading, fetchedData ] = useDicecloud(props.selectedChar);
let loadedCharacter = null;
if(fetchedData) {
loadedCharacter = {
name: fetchedData[0].Name,
alignment: fetchedData[0].Alignment,
/* a few more assignments */
};
}
let content = <p>Loading characters...</p>;
if(!isLoading && fetchedData && fetchedData.length > 0) {
content = (
<React.Fragment>
<Character
name={loadedCharacter.name}
alignment={loadedCharacter.alignment}
/* a few more props */ />
</React.Fragment>
)
}
return content;
}
export const Component2 = (props) => {
const [ fetchedData, error, isLoading ] = useHandbook('https://cors-anywhere.herokuapp.com/http://dnd5eapi.co/api/spells/?name=Aid')
let content = <p>Loading spells...</p>;
if(!isLoading && fetchedData) {
/* useHandbook used to return text to user in a string in some situations */
if(typeof fetchedData === 'string') {
content = (
<React.Fragment>
<p> {fetchedData} </p>
</React.Fragment>
)
} else {
content = (
<React.Fragment>
<Spellbook
/* the component that will in the future render the data from the API called in useHandbook */
/>
</React.Fragment>
)
}
}
return content;
}
I have been working on this issue for a few days and it is getting more confusing as I go along. I expected the mistake to be in useHandbook, but after many remakes it does not seem to be. The current useHandbook is very simple as shown below.
export const useHandbook = (url) => {
const [ isLoading, setIsLoading ] = useState(false);
const [ error, setError ] = useState(null);
const [ data, setData ] = useState(null);
const fetchData = async () => {
setIsLoading(true);
try {
const res = await fetch(url, {
method: "GET",
mode: 'cors'
});
const json = await res.json();
setData(json);
setIsLoading(false);
} catch(error) {
setError(error);
}
};
useEffect(() => {
fetchData();
}, []); //From what the documentation says, this [] should stop it from running more than once.
return [ data, error, isLoading ];
};
EDIT: I ran the chrome developer tools with the react extension and saw something that might be useful:
Image showing Component2 (Spellbook) run inside itself infinite times
You can modify your custom hook useHandbook's useEffect hook to have URL as dependency, since useEffect is similar to componentWillMount, componentDidUpdate and componentWillUnmount, in your case it is componentDidUpdate multiple times. So what you can do is.
useEffect(() => {
fetchData();
}, [url]);
Since there is no need to fetch data agin unless URL is changed
I found the mistake. Component2's real name was Spellbook which I had also called the rendering component that I had not yet made. It turns out I was calling the component from within itself.
Easy to see in the image at the edit part of the question.

React Komposer + Container Pattern + Data Input

I'm now working with react-komposer and the container/component pattern, but it's left me wondering how to handle data input.
For example, an AddVehicleForm component has a container that pre-populates some fields with data from the database. With the standard React Komposer examples, this makes sense:
import { composeWithTracker } from 'react-komposer';
import { Vehicles } from '../../collections/vehicles.js';
import AddVehicleForm from '../components/AddVehicleForm.jsx';
const composer = ( props, onData ) => {
const subscription = Meteor.subscribe( 'vehicles' );
if ( subscription.ready() ) {
const curVehicles = Vehicles.find().fetch();
onData( null, { curVehicles } );
}
};
const Container = composeWithTracker( composer )( AddVehicleForm );
But, to keep the component truly unreliant on it's data source, you would also need to pass it a handleSubmit() function to submit to the database, would you not? Where would you put this function?
Alternatively, I can see how it wouldn't be hard to solve using TrackerReact. But, as React Komposer is so widely adopted, what's the common way to handle this case?
EDIT:
Just throwing out an idea, but is there any reason not to create a container component with submit handling methods and then wrap that with the composer function? Something akin to this:
import {composeWithTracker} from 'react-komposer';
import ClassroomDashboard from '/imports/components/classroomDashboard/ClassroomDashboard.jsx';
class ClassroomDashboardContainer extends React.Component {
onSubmitHandle(e) {
// check form data and submit to DB
}
render() {
return(
<ClassroomDashboard {...this.props} onSubmit={this.onSubmitHandle.bind(this)} />
)
}
}
function composerFunction(props, onData) {
const handle = Meteor.subscribe('classroom');
if (handle.ready()) {
const classroom = Classrooms.findOne(props.params.id);
onData(null, {classroom});
};
};
export default composeWithTracker(composerFunction)(ClassroomDashboardContainer);

Resources