Unexpected token error in React app - javascript

Ok so I have an issue where I've been following along with a Udacity course.
The problem is the entire course app has been contained in one file and has steadily become harder and harder to pore through to find where issues are.
At some point an error has crept in, I think it's a syntax error, where I've added or missed out a bracket or something along those lines, but I can't find where it's happened.
I think it's specific to the below App component but can't see what I have done wrong.
The syntax highlighting in VS Code points to the below line where const is not highlighted as it is in other areas of the code.
const Context = React.createContext()
class App extends React.Component {
const Context = React.createContext()
class ConnectedApp extends React.Component {
render() {
return (
<Context.Consumer>
{(store) => (
<App store={store}/>
)}
</Context.Consumer>
)
}
}
class Provider extends React.Component {
render() {
<Context.Provider value={this.props.store}>
{ this.props.children }
</Context.Provider>
}
}
componentDidMount () {
const { store } = this.props
store.dispatch(handleIitialData())
store.subscribe( () => this.forceUpdate())
}
render() {
const { store } = this.props
const { todos, goals, loading } = store.getState()
if(loading) { return <h3>Loading</h3> }
return(
<div>
< Todos todos={todos} store={this.props.store} />
< Goals goals={goals} store={this.props.store} />
</div>
)
}
}
Error
babel.min.js:27 Uncaught SyntaxError: Inline Babel script: Unexpected token (108:18)
106 | class App extends React.Component {
107 |
> 108 | const Context = React.createContext()
| ^
109 |
110 | class ConnectedApp extends React.Component {
111 | render() {
at r.l.raise (babel.min.js:27)
at r.c.unexpected (babel.min.js:27)
at r.c.expect (babel.min.js:27)
at r.m.parseMethod (babel.min.js:27)
at r.parseClassMethod (babel.min.js:28)
at r.m.parseClassBody (babel.min.js:27)
at r.m.parseClass (babel.min.js:27)
at r.m.parseStatement (babel.min.js:27)
at r.parseStatement (babel.min.js:27)
at r.m.parseBlockBody (babel.min.js:27)

This is because the syntax you are trying to use in that class is not in your babel configuration or supported by your engine (node / browser) (and it is just a proposal for the class public fields proposal).
You should rather add support for that syntax in your babel (stage-3), knowing that there is a risk for this syntax to not pass as a final feature of the language.
Or declare the Context constant outside the class (or inside the constructor of the class and then access it using this context).
Example (from the official documentation but adapted to your code):
// the Context is created outside App
const Context = React.createContext();
// Also ConnectedApp and Provider are OUTSIDE App (The console doesnt complain now, but it will after you fix the one with const)
class Provider extends React.Component {
render() {
<Context.Provider value={this.props.store}>
{ this.props.children }
</Context.Provider>
}
}
class App extends React.Component {
componentDidMount () {
const { store } = this.props
store.dispatch(handleIitialData())
store.subscribe( () => this.forceUpdate())
}
render() {
const { store } = this.props
const { todos, goals, loading } = store.getState()
if(loading) { return <h3>Loading</h3> }
return(
<div>
< Todos todos={todos} store={this.props.store} />
< Goals goals={goals} store={this.props.store} />
</div>
)
}
}
// ConnectedApp goes after App since it uses App internally
class ConnectedApp extends React.Component {
render() {
return (
<Context.Consumer>
{(store) => (
<App store={store}/>
)}
</Context.Consumer>
)
}
}
There are other React concept errors in your code, but since you are following a course I guess this is intentional by the moment.

Related

React Component Inheritance to use parent method and child method

Background
I created a fully functional component. The component has state and props, and there are many methods inside. My component should work differently according to the os(ios / android). So I solved this problem by if statement like below.
if( platform.os == 'ios') { ... } else { ... }
The problem was that as the code volume increased, there was a problem with readability, and I decided to make a separate component for IOS and for Android. The first thing that came to mind was inheritance because ES6 and Typescript Support Class. The picture of concept is this.
However, React does not recommend inheritance. So I was just going to hand over the functions overridden by props to the Speech component in the SpeechIOS component's render function.
The code is as follows.
Speech.tsx
type Props = {
team: number,
onSpeechResults: (result: string) => void
...
}
type States = {
active: boolean;
error: string;
result: string;
...
};
export default class Speech extends Component<Props,States> {
state = { ... };
constructor(props: Props) {
super(props);
...
}
// render
render() {
...
return (
<ImageBackground source={require("../images/default-background.jpeg")} style={styles.full}>
...
</ImageBackground>
);
}
sendCommand = (code: number, speed: number, callback?: () => void) => { ... }
getMatchedSpell = (spellWord: string): { code: number, speed: number } => { ... }
onSpeechResults(e: Voice.Results) { ... };
...
}
SpeechIOS.tsx
import Speech from './Speech';
type Props = {}
type States = {}
export default class SpeechIOS extends Component<Props,States> {
constructor(props: Props) {
super(props);
...
}
// render
render() {
...
return ( <Speech team="1" onSpeechResults={this.onSpeechResults}></Speech> );
}
sayHello() {
console.log("Hello!!");
}
// I want that Speech Component call this onSpeechResults function
onSpeechResults(result: string) {
this.setState({...});
let temp = this.getMatchedSpell( ... ); // which is in Speech Component
this.sendCommand( 10, 100 ... ); // which is in Speech Component
this.sayHello(); // which is in SpeechIOS component only
... other things..
};
}
Problem.
As you can see, the onSpeechResults which is in SpeechIOS Component use some functions in Speech Component and in SpeechIOS Component also.
So, How to solve this problem? Should I use Inheritance?
Alternatively, break out any common logic into a utility function like SpeechUtil.ts, a whole new file that holds this shared logic and each util function, and exports them. Then, each component separately imports them. That ensures that if you ever update that logic it affects both components
You should define a top level component that defines the shared props and methods, and use those to render either your ios or android component. pass the props and methods to the children. This is composition which is favored over inheritance in react. example:
class Speech extends React.Component {
state ={shared: 'state'}
sharedMethod = () => {
this.setState({blah: 'blah})
}
render() {
const Root = Platform.select({
ios: SpeechIOS,
android: SpeechAndroid
})
return <Root onClick={this.sharedMethod} shared={this.state.shared}/>
}
}
You can use React.createRef for this purpose.
Below is an example code.
import Speech from './Speech';
type Props = {}
type States = {}
export default class SpeechIOS extends Component<Props, States> {
constructor(props: Props) {
super(props);
this.speech = React.createRef();
}
// render
render() {
...
return (<Speech ref={this.speech} team="1" onSpeechResults={this.onSpeechResults}></Speech>);
}
sayHello() {
console.log("Hello!!");
}
// I want that Speech Component call this onSpeechResults function
onSpeechResults(result: string) {
this.setState({ ...});
let temp = this.speech.current.getMatchedSpell(... ); // which is in Speech Component
this.sendCommand(10, 100 ... ); // which is in Speech Component
this.sayHello(); // which is in SpeechIOS component only
...other things..
};
}

React anti pattern?

Is the following an anti pattern in React? I like the pattern because it gives me context in static functions when a component has been instantiated. Then later I can import the class and call a static method to modify state. Or can this be done in a better way?
// componentA.js
function bleedContext() {
ComponentA.staticMethod = ComponentA.staticMethod.bind(this)
}
export default class ComponentA {
static staticMethod() {
this.setState({foo: 'bar'})
}
constructor() {
this.state = {}
bleedContext.call(this)
}
render() {
return (
...
)
}
}
// componentB.js
import ComponentA from 'path/to/componentA'
export default class ComponentB {
handleClick() {
ComponentA.staticMethod()
}
render() {
return (
<button onClick={this.handleClick} />
)
}
}
This is clearly an antipattern and possibly a mistake, depending on conditions. Static class method shouldn't operate with class instance. staticMethod is bound to specific component instance and uses setState, this could be only justified a class is a singleton (though a singleton is often an antipattern, too). This will result in bugs and memory leaks if more than one class instance is expected, and every React component is expected to have more than one instance, at least for testing.
A proper way for two independent components to interact with each other in React is to have a common parent component that provides this interaction, e.g.:
class ModalContainer extends Component {
modalRef = React.createRef();
render() {
return <>
<Modal ref={this.modalRef} />
<SomeComponentThatUsesModal modalRef={this.modalRef} />
</>;
}
}
The problem with example above is that this will require to pass modalRef prop deeply if <SomeComponentThatUsesModal> is nested.
This problem is solved with React context or other third-party global state solutions like Redux.
This can be done with React 16.3 context API, considering that Modal class instance has open method:
const ModalContext = React.createContext();
function getModal(modalRef) {
return {
open: data => modalRef.current.open(data);
close: () => modalRef.current.close();
}
}
class ModalContainer extends Component {
modalRef = React.createRef();
render() {
return <>
<Modal ref={this.modalRef} />
<ModalContext.Provider value={getModal(this.modalRef)}>
{this.props.children}
</ModalContext.Provider>
</>;
}
}
Then for any deeply nested component modal object with open and close methods will be available via context:
const SomeComponentThatUsesModal = props => <div>
<ModalContext.Consumer>
{modal => <button onClick={() => modal.open('foo')} />}
</ModalContext.Consumer>
</div>;
<ModalContainer>
...deeply nested component
<SomeComponentThatUsesModal />
...
</ModalContainer>
Here's a demo.

React Context error on rendering

I created an app to learn ReactJS. Unfortunately, when I was trying to use context I got 1 error on rendering, but my app compiles well.
This is my code:
import React, {Component} from 'react';
const LoginContext = React.createContext(null);
const user = {
isLoggedIn: true,
username: 'test',
};
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: false,
user: user,
};
}
render() {
return (
<LoginContext.Provider user={this.state.user}>
<Welcome/>
</LoginContext.Provider>
);
}
}
class Welcome extends Component {
render() {
return (
<div>
<WelcomeText/>
</div>
);
}
}
class WelcomeText extends Component {
render() {
return (
<LoginContext.Consumer>
<div>
{(user) => (<p>{user.username}</p>)}
</div>
</LoginContext.Consumer>
);
}
}
export default App;
This is the error:
updateContextConsumer
http://localhost:3000/static/js/bundle.js:20927:23
20924 | {
20925 | ReactCurrentOwner.current = workInProgress;
20926 | ReactDebugCurrentFiber.setCurrentPhase('render');
> 20927 | newChildren = render(newValue);
| ^ 20928 | ReactDebugCurrentFiber.setCurrentPhase(null);
20929 | } // React DevTools reads this flag.
20930 |
Can you help me solve this?
ContextProvider needs a prop called value and not user
<LoginContext.Provider value={this.state.user}>
<Welcome/>
</LoginContext.Provider>
Also the Context consumer has the children as a function and not the div
class WelcomeText extends Component {
render() {
return (
<LoginContext.Consumer>
{(user) => (<div><p>{user.username}</p></div>)}
</LoginContext.Consumer>
);
}
}
I am currently working on React-16.8.6 and having an interesting bug.
I'm not sure if it's the known issue or not but I am having the same error whenever I have a space between two characters '}' and '<' as you can see it line-30.
After (1) removing the space or (2) completely making a new line with , it was resolved.
Even though I love React a lot, it's not perfect and we can make it better together.

React. How to collect and transfer the collection of nodes as props to children

So, I try to collect the nodes after that the page are builded in the module iteamsHolder. It works for main App component and it see all collected iteams when I invoke the module iteamsHolder inside it.
But when I try to transfer the iteamsHolder module with iteams to children componennts of App, I have an error or undefined for this module iteams. So, I understand that the problem is in the component queue render. But how we can solve that error?
/* MAIN APP COMPONENT */
import iteamsHolder from '../view/iteamsHolder'
import sidebarWidgetHide from '../view/sidebarWidgetHide'
class App extends React.Component {
constructor(props) {
super(props);
this.handleKeyCode = this.handleKeyCode.bind(this);
this.handleClick = this.handleClick.bind(this);
}
render() {
return (
<Fragment>
<Preloader/>
<LeftSideInfo state={this.state.toggle} updateState={this.updateState}
coordY={this.state.coordY}/>
<MenuButtonOpen state={this.state.toggle} updateState={this.updateState}
iteamsHolder={iteamsHolder().iteamsMain}/> // this is where I'm
// trying to transfer the iteams module.
</Fragment>
)
}
/* ITEAM HOLDER MODULE */
const iteamsHolder = () => {
if (document.readyState === "complete") {
let iteamsMain = {
sidebar: document.querySelector('.left-side__column'),
rightColumn: document.querySelector('.right-side__column')
};
let iteamsSupport = {
header: document.querySelectorAll('.menu-button__container'),
menuButton: document.querySelectorAll('.menu-button'),
menuName: document.querySelector('.personal-name'),
experienceblock: document.querySelector('.block-headline.block-headline__experience')
};
return { iteamsMain, iteamsSupport };
} else {
return 'Sorry';
}
};
export default iteamsHolder;
/CHILD COMPONENT WITH NESTED ITEAMS MODULE/
class MenuButtonOpen extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.handleScroll = this.handleScroll.bind(this);
}
render() {
return (
{console.log(this.props.iteamsHolder)} // undefined of error
)
}
You're getting undefined because iteamsHolder is returning the default value 'Sorry', not the object { iteamsMain, iteamsSupport }. If you change is to:
<MenuButtonOpen
state={this.state.toggle}
updateState={this.updateState}
iteamsHolder={iteamsHolder()}
/>
you'll see that 'Sorry' is being passed to the component. This is because when iteamsHolder is being evaluated, the webpage is not yet fully loaded. Without knowing why you've structured your code the way you did, I can't make a good suggestion on how to "fix" it. What may help is looking at how document.readyState works and reading through suggestions like what's listed here.

React js access to the state of another class

How can I access the state of another class.
This construction does not work
class classname2 extends React.Component {
...
this.state = { statename1: "lala" };
...
};
class classname1 extends React.Component {
render() {
return (
{classname2.state.statename1 }
);
}
};
As mentioned in the comments, pass state as props to their children.
class classname2 extends React.Component {
this.state = { statename1: "lala" };
render() {
return <classname1 statename1={this.state.statename1} />
}
};
class classname1 extends React.Component {
render() {
return (
<div>{this.props.statename1}</div>
);
}
};
An often used pattern is passing arbitrary props down the component tree:
const {needThisOne, andThisOne, ...props} = this.props;
// do stuff with needThisOne andThisOne
// and pass the remaining props down:
return <Component {...props} />;
An update for hooks, because why not.
const ParentComponent = ({...props}) => {
const [stateName1, setStateName1] = useState('defaultValue');
return <ChildComponent stateName1={stateName1} {...props} />;
}
const ChildComponent = ({stateName1, ...props}) => (
<span>{stateName1}</span>
);
Shared state between components by direct access is an anti-pattern. Each component should have its own state. If you need globally a available state, please consider using Redux.
It may sound a bit cumbersome at first but it's awesome and it allows your app to be properly tested.
Edit:
Passing state as props is also valid, but it only works when components are in parent-child order. Redux allows components to be updated no matter what their relationship is

Categories

Resources