#withRouter Unexpected Token Error - reactjs

Seems every time I have to setup React Router in a new project I run into something new possibly by version changes.
I am using reactjs and mobx state tree(though at this point have not used anything of it).
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import HomeComponent from './HomeComponent.js';
import {withRouter, Route} from 'react-router'
#withRouter
export default class App extends Component {
render() {
return (
<Route exact path='/' component={HomeComponent}/>
);
}
}
export default App;
When I run it I get
ERROR in ./src/components/App.js
Module build failed: SyntaxError /components/App.js: Unexpected token (6:0)
I also get some warning as well
Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning.
Edit
Per the comment from "Artem Mirchenko"
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'mobx-react';
import { useStrict } from 'mobx';
import createBrowserHistory from 'history/createBrowserHistory';
import {syncHistoryWithStore } from 'mobx-react-router';
import { Router } from 'react-router'
import AppContainer from './components/App';
const browserHistory = createBrowserHistory();
import stores from '../src/stores/Stores';
const history = syncHistoryWithStore(browserHistory, stores.routingStore);
ReactDOM.render(
<Provider {... stores}>
<Router history={history}>
<AppContainer />
</Router>
</Provider>,
document.getElementById('app')
);
import {RouterStore} from 'mobx-react-router';
const routingStore = new RouterStore();
const stores = {
routingStore
}
export default stores;

You need to install babel plugin transform-decorators-legacy.
Via yarn:
yard add --dev transform-decorators-legacy
Vie npm:
npm install --save-dev transform-decorators-legacy
And add in to plugins ket in you babel options:
{
// pressets ....
"plugins": ["transform-decorators-legacy"]
}

Related

ComponentDidMount called twice

ComponentDidMount in my overarching App component is being called twice, and I can't figure out why. So far google suggests this is usually due to a lack of keys that means the app has to assume things have changed and delete everything instead of just the relevant portion of the DOM, but I stripped my app as bare as I can get reasonably get it and it's still happening.
index.tsx:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App global={{baseUrl: "http://localhost", port: 54887}} />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
reportWebVitals();
App.tsx:
import React from 'react'
import CurrentItems, { CurrentItemsProps } from './CurrentItems';
import Navigation, { NavigationProps } from './Navigation';
import { CombinedNavigationProps } from './Navigation';
import './App.css';
import { GlobalProps } from './GlobalProps';
interface AppProps extends GlobalProps {}
interface AppState {
navigation: NavigationProps;
}
class App extends React.Component<AppProps, AppState> {
constructor(props: AppProps){
super(props);
//this.onSelectedViewChange = this.onSelectedViewChange.bind(this);
}
componentDidMount(){
console.log("app did mount");
}
onSelectedViewChange(view: string) {
}
render(){
if(this.state === undefined || this.state === null){
return (<div>Loading...</div>);
} else {
return (
<div>
Loaded.
</div>
);
}
}
}
export default App;
Link to github for full code
Screenshot of console output:
Per #NicholasTower's comment, it's because I'm using strict mode. Seems like it's time to learn about Hooks! Guess I didn't go far enough in the ReactJS introduction documentation.

Error message with: Web3 + create-react-app + webpack 5

I am writing the frontend for a Dapp.
I have the script /src/config/index.js
import Web3 from 'web3';
const getLibrary = (provider) => {
return new Web3(provider);
};
export { getLibrary };
And the /src/index.js where I am trying to import getLibrary:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { HashRouter } from 'react-router-dom';
import { ChakraProvider } from '#chakra-ui/react';
import { Web3ReactProvider } from '#web3-react/core';
import { getLibrary } from './config/web3';
ReactDOM.render(
<React.StrictMode>
<HashRouter>
<ChakraProvider>
<Web3ReactProvider getLibrary={getLibrary}>
<App />
</Web3ReactProvider>
</ChakraProvider>
</HashRouter>
</React.StrictMode>,
document.getElementById('root')
);
But, I have the error
The line responsible for the error is:
import { getLibrary } from './config/web3';
I used create-react-app to build the project.
I have try several ideas but nothing is working for me... any help, please?
I had the same problem when using web3 with react and webpack 5. This helped me solve it. I followed option #1 as I couldn't get the other option to work (my main confusion being where to keep webpack.config.js since I had kept it at the root and it was not being picked up).
For anyone looking to resolve this still (2022-08-30), I recommend reading this article:
https://alchemy.com/blog/how-to-polyfill-node-core-modules-in-webpack-5
It will be different in regards to your dependencies but it helped resolve my issues. It basically adds support back in by rerouting requests to dependencies using the react-app-rewired package.

Redux TS Generic type 'Dispatch<S>' requires 1 type argument(s)

Trying to setup a project with typescript and redux.
I am getting this error
Generic type 'Dispatch<S>' requires 1 type argument(s).
here is my store.ts
import { connectRouter, routerMiddleware } from 'connected-react-router'
import { applyMiddleware, compose, createStore } from 'redux'
import { createLogger } from 'redux-logger'
import ReduxThunk from 'redux-thunk'
import { createBrowserHistory } from 'history'
import reducers from './reducers'
import { composeWithDevTools } from 'redux-devtools-extension'
export const history = createBrowserHistory()
const composeEnhancers = composeWithDevTools({
// Specify name here, actionsBlacklist, actionsCreators and other options if needed
})
const logger = createLogger()
const middleware = [ReduxThunk, logger]
const Store = createStore(connectRouter(history)(reducers), {}, composeEnhancers(applyMiddleware(...middleware, routerMiddleware(history))))
export default Store
here is root reducer
import { combineReducers } from 'redux'
import { ActionType } from 'typesafe-actions'
import * as actions from '../actions'
export interface IState {
test: string
}
export type Actions = ActionType<typeof actions>
export default combineReducers<IState, Actions>({
test: () => 'hey'
})
and here are some dummy actions
import { action } from 'typesafe-actions'
export const toggle = (id: string) => action('TOGGLE', id)
// (id: string) => { type: 'todos/TOGGLE'; payload: string; }
finally here is index.ts
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import App from './App'
import './index.scss'
import registerServiceWorker from './registerServiceWorker'
import store, { history } from './store'
import { Provider } from 'react-redux'
import { Route, Switch } from 'react-router' // react-router v4
import { ConnectedRouter } from 'connected-react-router'
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}> { /* place ConnectedRouter under Provider */}
<div> { /* your usual react-router v4 routing */}
<Switch>
<Route exact path="/" render={() => (<div>Match</div>)} />
<Route render={() => (<div>Miss</div>)} />
</Switch>
</div>
</ConnectedRouter>
</Provider>,
document.getElementById('root') as HTMLElement
)
registerServiceWorker()
Here seems to be a similar issue without solution yet
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/9611
But I am new to typescript so might be missing something basic
It looks to me like you are indeed facing the same issue you linked. While we wait and see if 7mllm7's pull request is merged, you can use his modified version of the react-redux types. I'd recommend the following approach:
git clone --depth=1 https://github.com/7mllm7/DefinitelyTyped
Copy the types/react-redux folder into your project (suppose for example you copy it to a folder named react-redux.fixed).
Edit react-redux.fixed/package.json to replace "private": "true" with "name": "#types/react-redux".
In your package.json, specify the version of #types/react-redux as ./react-redux.fixed.
Run npm install. npm will make a symlink from node_modules/#types/react-redux to react-redux.fixed.
Compared to just editing the file in node_modules/#types/react-redux, this way npm knows you are using a modified version of the package and won't overwrite it. (This process deserves to be widely known; I'll find a better place to document it if I have time.)
I solved this by downgrading to Redux 3.7. It has proper typings (There still aren't typings for Redux 4.0). There are some Github issues where they discuss about it (here and here).

Dynamic imports in React

I am trying to import dynamic of a file by means of process.env.NODE_ENV to import a style sheet or another one in production or in development. I have made a condition to load it but it gives me an error Error in ./src/index.js
Syntax error: 'import' and 'export' may only appear at the top level (13: 4) I guess this is not correct but ... how can I do it? I use create-react-app
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './components/App';
import routes from './routes';
import configureStore from './store/configureStore';
import initialState from './reducers/initialState';
if (process.env.NODE_ENV === 'production') {
import './styles/index.css';
}else {
import './styles/index.scss';
}
const store = configureStore(initialState);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Thanks!!!
As Laoujin mentions in the comments, you'll want to use require in this scenario.
For example, here's how I configure access to my Redux store, based on NODE_ENV, which could be adjusted to suit your needs:
const INITIAL_STATE = {};
function getStore () {
const configureStore = process.env.NODE_ENV === 'production'
? require('./configure-store.prod').default
: require('./configure-store.dev').default;
return configureStore(INITIAL_STATE);
}
export default getStore();

How to configure a basename in React Router 3.x

I have an app running at a nested url as opposed to the root. Lets say example.com/app.
I read here that in react router 2.x you could configure basenames.
How can this be done in react router 3.x?
FYI I am also using the react-router-redux package.
This functionality does not exist in React Router anymore. I went through a similar problem and found this fix.
Step 1: Install History (3.0.0)
npm install --save history#3.0.0
Step 2: Import { useBasename } from history in your router file (the file with <Router>):
import { useBasename } from 'history'
Step 3: Modify your <Router> like the below example:
<Router history={ useBasename(() => browserHistory)({ basename: '/app' }) }>
I think the section on configuring histories in the React Router docs is what you're looking for:
https://github.com/ReactTraining/react-router/blob/v3/docs/guides/Histories.md#customize-your-history-further
Here's a full example integrating with react-router-redux (with some unnecessary info excluded):
import React from 'react';
import ReactDOM from 'react-dom';
import createBrowserHistory from 'history/lib/createBrowserHistory';
import { useRouterHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import Root from './containers/Root';
import configureStore from './store/configureStore';
const historyConfig = { basename: '/some-basename' };
const browserHistory = useRouterHistory(createBrowserHistory)(historyConfig);
const store = configureStore({ initialState, browserHistory });
const history = syncHistoryWithStore(browserHistory, store, {
selectLocationState: (state) => state.router,
});
ReactDOM.render(
<Root history={history} store={store} />,
document.getElementById('root')
);

Resources