React - Babel not transpiling files - javascript

I am going over a routing lessons for React
After lots of attempts, I got a working application, I can use:
var react = require("react");
var Render = require('react-dom');
Render((
<Router history={hashHistory}>
<Route path="/about" component={About}/>
</Router>
), document.getElementById('app'))
However majority of the examples on the web are using import statements, so for example:
import { Router, Route, hashHistory } from 'react-router'
render((
<Router history={hashHistory}>
<Route path="/" component={App}/>
</Router>
), document.getElementById('app'))
Produces following error in my broswer:
(render is not defined).
This is my web.pack.config:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: [
'./src/app.js'
],
output: {
path: path.join(__dirname, 'public/js'),
filename: 'app.built.js'
},
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?
presets[]=es2015&presets[]=react'
}
]
}
}
What do I have to do so I can start using import statements?

The error is because you are not importing the ReactDOM. The best way to do it is
import React from "react";
import ReactDOM from "react-dom";
import { Router, Route, IndexRoute, hashHistory } from "react-router";
import App from "./App";
const app = document.getElementById('app');
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={App}></Route>
</Router>, app);
Considering that you have a component called App in the same directory like this:
App.js
import React from "react";
export default class App extends React.Component {
render() {
return (
<div>My App!</div>
);
}
}

Related

React - Invalid Hook Call: convert App component to functional component, still get Invalid Hook Call

I have tried to create a simple app that allows a user to create or edit exiting 'projects'.
I am running in to the error:
react.development.js:1476 Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
//
at Routes (http://localhost:3000/static/js/bundle.js:154234:5)
at App
//
The code for my 'App.js' is:
import React from "react";
import { Routes, Route } from "react-router-dom";
import MainPage from "./MainPage";
//import LoginPage from "./LoginPage";
//<Route path="/login" element={<LoginPage />} />;
const App = () => {
return (
<Routes>
<Route path="/projects" element={<MainPage />} />
</Routes>
);
};
export default App;
Nothing renders in the browser but the console throws the above error. I thought the error was related to using a functional component, but that doesn't seem to fix it (or more likely I'm too daft to figure out what I've done wrong).
I originally had the following code:
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import MainPage from './MainPage';
import LoginPage from './LoginPage';
const App = () => (
<Router>
<Switch>
<Route path="/login" component={LoginPage} />
<Route path="/projects" component={MainPage} />
</Switch>
</Router>
);
export default App;
I realised 'switch' needed to be replaced with 'routes' and based on other online documentation used the 'elements' prop instaed of the component prop.
import React from 'react';
import { Routes, Route } from 'react-router-dom';
import MainPage from './MainPage';
import LoginPage from './LoginPage';
const App = () => {
return (
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/projects" element={<MainPage />} />
</Routes>
);
};
export default App;`
Clearly this wan't the solution.
My MainPage.js code is:
import React, { useState, useEffect } from 'react';
import {
Button,
DataTable,
TableContainer,
Table,
TableHead,
TableRow,
TableBody,
TableCell,
} from 'carbon-components-react';
const MainPage = () => {
// State for the list of projects
const [projects, setProjects] = useState([]);
// Fetch the list of projects from the server when the component mounts
useEffect(() => {
fetch('/api/projects')
.then((res) => res.json())
.then((data) => setProjects(data.projects));
}, []);
// Function to handle creating a new project
const handleCreateProject = () => {
// Display a form for the user to enter the project's name
const projectName = window.prompt('Enter the name of the new project:');
// If the user entered a name, create the new project and add it to the list
if (projectName) {
fetch('/api/projects', {
method: 'POST',
body: JSON.stringify({ name: projectName }),
headers: { 'Content-Type': 'application/json' },
})
.then((res) => res.json())
.then((data) => setProjects([...projects, data.project]));
}
};
return (
<div>
<h1>My Projects</h1>
<Button onClick={handleCreateProject}>Create New Project</Button>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
</TableRow>
</TableHead>
<TableBody>
{projects.map((project) => (
<TableRow key={project.id}>
<TableCell>{project.name}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</div>
);
};
export default MainPage;
The LoginPage was just a placeholder (removed in the updated App.js).
My index.js code is:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
My package.json dependencies are:
"dependencies": {
"#testing-library/jest-dom": "^5.16.5",
"#testing-library/react": "^13.4.0",
"#testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
Update:
Updated App.js now using RouterProvider, createBrowserRouter. This is now throwing a browser console error:
Cannot read properties of undefined (reading 'map')
This seems to be coming from
return routes.map((route) => {
In the components.tsx file.
Current App.js code is:
import React from "react";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { Routes, Route } from "react-router-dom";
import MainPage from "./MainPage";
//import LoginPage from "./LoginPage";
const router = createBrowserRouter();
const routes = [
{ path: "/projects", element: <MainPage /> },
//{ path: '/login', element: <LoginPage /> },
// add more routes here
];
const App = () => {
return (
<RouterProvider router={router}>
<Routes>
{routes.map((route) => (
<Route path={route.path} element={route.element} />
))}
</Routes>
</RouterProvider>
);
};
export default App;
The initial code:
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import MainPage from './MainPage';
import LoginPage from './LoginPage';
const App = () => (
<Router>
<Switch>
<Route path="/login" component={LoginPage} />
<Route path="/projects" component={MainPage} />
</Switch>
</Router>
);
export default App;
When you updated from react-router-dom v5 to v6, i.e. replace the Switch component with the Routes component and changed the Route props, you appear to have dropped the Router component. A router is still required.
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import MainPage from './MainPage';
import LoginPage from './LoginPage';
const App = () => (
<Router>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/projects" element={<MainPage />} />
</routes>
</Router>
);
export default App;
You shared your project's dependencies but I don't see react-router-dom listed as a project dependency. Ensure react-router-dom is actually installed and that the package.json file lists it as a dependency.
npm install --save react-router-dom#6
If you are trying to use the newer RRDv6.4+ Data APIs then you specify all the routes in the createBrowserRouter function. In your example it's not passed an array of routes, so this seems to be the cause of the mapping error. Pass the routes configuration array to createBrowserRouter. The RouterProvider also takes no children, it's self-closed.
import React from "react";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { Routes, Route } from "react-router-dom";
import MainPage from "./MainPage";
import LoginPage from "./LoginPage";
// Routes configuration array
const routes = [
{ path: "/projects", element: <MainPage /> },
{ path: '/login', element: <LoginPage /> },
// add more routes here
];
// Pass configuration array
const router = createBrowserRouter(routes);
const App = () => {
return (
<RouterProvider router={router} />
);
};
If you are using latest react-router-dom v6.4+ then you need to add RouterProvider in your root file and create router configuration using createBrowserRouter .
Update your index.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import MainPage from "./MainPage";
import LoginPage from "./LoginPage";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
const router = createBrowserRouter([
{
path: "/",
element: <MainPage />
},
{
path: "/login",
element: <LoginPage />
}
]);
root.render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>
);

react-router-dom v6 renders only default route

I'm starting a new project using React Router Dom v6 and I'm in trouble with one of the first steps: setting the routes for the App.
I just created two pages: AuthPage and DashboardPage and I would like to be able of rendering both of them if, from the browser, I navigate to:
localhost:PORT/ : should render DashboardPage
localhost:PORT/auth: should render AuthPage
but right no the only page rendered is DashboardPage even if I try to navigate to non-existing routes.
This is my code so far:
main.tsx
import { createRoot } from 'react-dom/client'
import { MemoryRouter as Router } from 'react-router-dom'
import { ThemeProvider } from '#mui/material/styles'
import { theme } from './theme'
import App from './App'
const root = createRoot(document.getElementById('root') as HTMLElement)
root.render(
<ThemeProvider theme={theme}>
<Router>
<App />
</Router>
</ThemeProvider>
)
App.tsx
import { Route, Routes } from 'react-router-dom'
import AuthPage from './pages/AuthPage'
import DashboardPage from './pages/DashboardPage'
import NotFoundPage from './pages/NotFoundPage'
import { routes } from './routes'
function App() {
return (
<Routes>
<Route path={routes.dashboard.url} element={<DashboardPage />} />
<Route path={routes.auth.url} element={<AuthPage />} />
<Route path={routes.notFound.url} element={<NotFoundPage />} />
</Routes>
)
}
export default App
routes.ts
export const routes = {
auth: {
url: '/auth'
},
dashboard: {
url: '/'
},
notFound: {
url: '*'
}
}
Use BrowserRouter instead of MemoryRouter :
import { createRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import { ThemeProvider } from '#mui/material/styles'
import { theme } from './theme'
import App from './App'
const root = createRoot(document.getElementById('root') as HTMLElement)
root.render(
<ThemeProvider theme={theme}>
<BrowserRouter>
<App />
</BrowserRouter>
</ThemeProvider>
)
As I know, exact option doesn't supported in react-router v6.
Try to use index option.
<Route path="/*">
<Route index element={< DashboardPage />} />
<Route path={routes.auth.url} element={<AuthPage />} />
// ... other routes
</Route>

React: App not rendering to screen when wrapped in React.Component

So, my app, after being wrapped in a class, no longer renders to the screen, and no errors are issued. Just a blank screen is displayed.
What am I overlooking here?
webpack.config
var path = require('path');
var webpack = require('webpack');
const Dotenv = require('dotenv-webpack');
module.exports = {
devtool: 'source-map',
entry: [
'webpack-hot-middleware/client',
'./client/index'
],
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new Dotenv({
path: './.env', // Path to .env file (this is the default)
safe: true // load .env.example (defaults to "false" which does not use dotenv-safe)
})
],
module: {
rules: [
// js
{
test: /\.js$/,
use: ['babel-loader'],
include: path.join(__dirname, 'client')
},
// CSS
{
test: /\.styl$/,
include: path.join(__dirname, 'client'),
use: [
'style-loader',
'css-loader',
'stylus-loader'
]
}
]
}
};
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import app from './app.js';
ReactDOM.render (
<app />,
document.getElementById('root')
)
app.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute, Redirect } from 'react-router'
import 'babel-polyfill';
import { ApolloProvider, graphql, gql } from 'react-apollo';
import client from './apolloClient';
import App from './components/App';
import Single from './components/Single';
import PhotoGrid from './components/PhotoGrid';
import LoginUser from './components/LoginUser';
import css from './styles/style.styl';
import store, { history } from './store';
import Raven from 'raven-js';
import { sentry_url } from './data/config';
if(window) {
Raven.config(sentry_url).install();
}
import * as OfflinePluginRuntime from 'offline-plugin/runtime';
if (process.env.NODE_ENV === 'production') {
OfflinePluginRuntime.install();
}
class app extends React.Component {
render () {
return (
<ApolloProvider store={store} client={client}>
{ /* Tell the Router to use our enhanced history */ }
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={PhotoGrid} />
<Route path="/view/:postId" component={Single}></Route>
<Route path="/login" component={LoginUser}></Route>
</Route>
</Router>
</ApolloProvider>
)
}
}
export default app;
But if I remove the class, as follows, and specify app.js as the entry: point in my webpack.config, then the app renders correctly:
render(
<ApolloProvider store={store} client={client}>
{ /* Tell the Router to use our enhanced history */ }
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={PhotoGrid} />
<Route path="/view/:postId" component={Single}></Route>
<Route path="/login" component={LoginUser}></Route>
</Route>
</Router>
</ApolloProvider>,
document.getElementById('root')
);
All react classes in jsx must have a capital first letter. You need to update your index.js accordingly
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app.js';
ReactDOM.render (
<App />,
document.getElementById('root')
)
If you were to look at the html output of your code you would likely see <app></app> where you expected your component to be inserted
what about try stateless component:
export default function App() {
return (
<ApolloProvider store={store} client={client}>
{ /* Tell the Router to use our enhanced history */ }
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={PhotoGrid} />
<Route path="/view/:postId" component={Single}></Route>
<Route path="/login" component={LoginUser}></Route>
</Route>
</Router>
</ApolloProvider>
)
}

React Router: Failed to Navigate Route

I setup simple route within my index.js file.
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
import reduxThunk from 'redux-thunk';
import '../less/app.less';
import reducers from './reducers';
import App from './components/App';
import Login from './components/auth/Login';
import Welcome from './components/Welcome';
// const defaultSetting = settings;
const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={Welcome} />
<Route path="login" component={Login} />
</Route>
</Router>
</Provider>
, document.querySelector('.container')
);
my App.js
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div>
{this.props.children}
</div>
);
}
}
export default App;
When I navigate to localhost:8080 using webpack-dev-server I can properly show my index route. but when I navigate to localhost:8080/login' it shows errorCannot GET /login`.
Any solution?
By default the server will look for an html file at the /login route. So you should configure it for html5 navigation to return you index.html for any route it receives.
EDIT:
To do so in webpack, as you suggest in the comments, you can add this to your webpack dev server config:
historyApiFallback: true
index.html should be the default, so no need to specify it.
Also please note that urls containing dots are still pointing to files and thus redirected to the server. For example, if you have an url such as /search/firsname.lastname you would need to add a handler for this.
historyApiFallback: {
rewrites: [
{
from: /^\/search\/.*$/,
to: function() {
return 'index.html';
}
}
]
},
See this issue for more info.

Why is this exception being thrown? Uncaught ReferenceError: React is not defined

import {Route, IndexRoute} from 'react-router'
import App from './App'
import Home from './Home'
import Repos from './Repos'
import Repo from './Repo'
import About from './About'
module.exports = (
<Route path="/" component={App}>
<IndexRoute component={Home} />
<Route path="/repos" component={Repos}>
<Route path="/repos/:userName/:repoName" component={Repo} />
</Route>
<Route path="/about" component={About}/>
</Route>
)
I didn't expect to have to import React here. Of course, the fix is easy. I just need to add the following:
import React from 'react'
What is puzzling to me is that React is not explicitly used in the code sample I pasted above. I guess it is being required when the Babel/JSX code is transpiled to JavaScript?
Could you tell me exactly why am I required to import React here?
You're correct, the code transpiled by Babel will use React.
You can check for yourself using the "try it out" feature of the Babel website to see what your code will be transpiled to.
In your case, you'll get
"use strict";
module.exports = React.createElement(
Route,
{ path: "/", component: App },
React.createElement(IndexRoute, { component: Home }),
React.createElement(
Route,
{ path: "/repos", component: Repos },
React.createElement(Route, { path: "/repos/:userName/:repoName", component: Repo })
),
React.createElement(Route, { path: "/about", component: About })
);
As you can see, React.createElement is called multiple times.

Categories