How to change base url in create-react-app? - reactjs

How to change base url in create-react-app? So that the application does not open with localhost:3000/, but localhost:3000/myurl?

You will need to do a lot of adjusting if you want react to launch in a subdir. like changing path of assets, components etc. This Guide is a good starting point
on how to accomplish your needs. Again Its not recommended, if you want like to switch to /myUrl as soons as it launches, you could do a componentDidMount() and force it there.

Assuming you are using react-router, you can achieve that by using a Redirect to navigate your app from / to /myurl.
First, declare a route config like this:
// routers.js
import React from "react";
import { Redirect } from "react-router-dom";
export const redirectRoutes = [
{
path: "/",
exact: true,
// handle redirect case: / -> /myurl/
render: () => <Redirect to={`/myurl`} />
}
]
Then, inside your App.js:
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { redirectRoutes } from "./routers.js";
// generate app reidrect routes
const redirectRouteComponents = redirectRoutes.map(route => (
<Route
key={route.path}
path={route.path}
exact={route.exact}
render={route.render}
/>
));
const App = () => <Router>{redirectRouteComponents}</Router>;

Related

Building an API, beside a (React/Firebase) web app

I have a web app using React and Firebase Realtime Database.
The index.js file looks like the following:
import React from 'react';
import { userInfo } from 'os'
import ReactDOM from 'react-dom/client';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
.....
class RouterBlock extends React.Component {
constructor(props) {
super(props);
this.state = {
logdInSatus: false
};
}
.....
render() {
.....
return (
<Router>
<Routes>
<Route exact path="/" element={<TopMenu/>} />
.....
<Route exact path="/p1" element={<Component_1/>} />
<Route exact path="/p2" element={<Component_2/>} />
<Route exact path="/p3" element={<Component_3/>} />
.....
</Routes>
</Router>
);
}
}
It all works pretty much the way I wish.
From this point, here is what I want:
An API for a customer, which is going to allow him to get data from my DB for his own use.
My app is now accessible through a URL like:
https://example.com/myWebApp
The API for the customer(s) should be used via this:
https://example.com/myAPI
and it would return JSON data from my DB that the customer can then use.
The top file for the API would probably look something like (but I am not yet sure):
const http = require("http")
import { getDatabase, ref, onValue} from "firebase/database";
import { url } from 'inspector'
import { workerData } from 'worker_threads'
const db = getDatabase();
.....
const requestListener = function (req, res) {
res.setHeader("Content-Type", "application/json")
res.writeHead(200)
res.end(`{"message": "This is a JSON response"}`)
// Here data needs to be taken from the actual DB.
}
const server = http.createServer(requestListener)
server.listen(port, host, () => {
console.log(`Server is running on http://${host}:${port}`)
})
Finally, my question is about the routing for the API url. Should it be one of the routes found in index.js or something totally separated? If this is the case (a route inside index.js), what is the proper syntax that I should use for this route? What I tried did not work.
Since all my current routes use a React component, I suppose this one needs to be different, but I don't know how to handle it. Any relevant hint will be welcome.

Performing a condition based on the current URL with react.js and react router v6

Using React.js & react router v6
Is there a way I can extract information from the current URL? Let's say my current URL is this: localhost:3000/about/x567gfh67ssd90g
I simply want to perform a condition based on the current URL. Is there any possible way of doing this?
import { useLocation } from "react-router-dom";
const Component = () => {
const location = useLocation();
useEffect(() => {
console.log(location);
});
return ();
};
You can get pathname using useLocation.
You can also add connected-react-router to your project. This way you will have access to all the current route information in your redux-store. This will also allow you to "Time travel" through your SPA. When you hit the backbutton instead of going to the previous page you can go back through state.
import React from 'react';
import { render } from 'react-dom';
import { Provider, ReactReduxContext } from 'react-redux';
import { ConnectedRouter } from "connected-react-router";
import { store, history } from './Store/store';
import { App } from './App/App';
render(
<Provider store={ store } context={ ReactReduxContext } >
<ConnectedRouter context={ ReactReduxContext } history={ history }>
<App />
</ConnectedRouter>
</Provider>,
document.getElementById('app')
);
If you install the redux-devTools in your browser you can look at all the URL data like this- Obviously this is a little more advanced but you it will give you access to everything you need.

React Router Path

I have a path.js file where it contains all the PATH Variable
export const PATH = {
USER: '/user/',
INFO: '/user/:user_id/'
}
when I try to access the PATH.INFO it doesn't go it's page but if I change INFO PATH it works.
Does /user/ and /user/:user_id/ mean same in react-router??
First of all, the answer of your question that weather the /user/ and /user/:user_id/
are same. No they are not same /user mean this static path where /user/:user_id mean this path and after /:user_id this value is dynamic and could b any thing. Also i notice that you have added an additional / at the end of your route.
Try this code it works
import React from "react";
import { Route } from "react-router-dom";
import TestCompOne from "./Components/TestCompOne/TestCompOne";
import TestCompTwo from "./Components/TestCompTwo/TestCompTwo";
import { PATH } from "./Route";
const app = () => {
return (
<div>
<Route path={PATH.USER} exact component={TestCompOne} />
<Route path={PATH.INFO} exact component={TestCompTwo} />
</div>
);
};
export default app;

Cannot read property 'history' of undefined (useHistory hook of React Router 5)

I am using the new useHistory hook of React Router, which came out a few weeks ago. My React-router version is 5.1.2. My React is at version 16.10.1. You can find my code at the bottom.
Yet when I import the new useHistory from react-router, I get this error:
Uncaught TypeError: Cannot read property 'history' of undefined
which is caused by this line in React-router
function useHistory() {
if (process.env.NODE_ENV !== "production") {
!(typeof useContext === "function") ? process.env.NODE_ENV !== "production" ? invariant(false, "You must use React >= 16.8 in order to use useHistory()") : invariant(false) : void 0;
}
return useContext(context).history; <---------------- ERROR IS ON THIS LINE !!!!!!!!!!!!!!!!!
}
Since it is related to useContext and perhaps a conflict with context is at fault, I tried completely removing all calls to useContext, creating the provider, etc. However, that did nothing. Tried with React v16.8; same thing.
I have no idea what could be causing this, as every other feature of React router works fine.
***Note that the same thing happens when calling the other React router hooks, such as useLocation or useParams.
Has anyone else encountered this? Any ideas to what may cause this?
Any help would be greatly appreciated, as I found nothing on the web related to this issue.
import React, {useEffect, useContext} from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Switch, useHistory } from 'react-router'
import { useTranslation } from 'react-i18next';
import lazyLoader from 'CommonApp/components/misc/lazyLoader';
import {AppContext} from 'CommonApp/context/context';
export default function App(props) {
const { i18n } = useTranslation();
const { language } = useContext(AppContext);
let history = useHistory();
useEffect(() => {
i18n.changeLanguage(language);
}, []);
return(
<Router>
<Route path="/">
<div className={testClass}>HEADER</div>
</Route>
</Router>
)
}
It's because the react-router context isn't set in that component. Since its the <Router> component that sets the context you could use useHistory in a sub-component, but not in that one.
Here is a very basic strategy for solving this issue:
const AppWrapper = () => {
return (
<Router> // Set context
<App /> // Now App has access to context
</Router>
)
}
const App = () => {
let history = useHistory(); // Works!
...
// Render routes in this component
Then just be sure to use the "wrapper" component instead of App directly.
Note to other people that run into this problem and already have wrapped the component with Router component. Make sure that Router and the useHistory hook are imported from the same package. The same error can be thrown when one of them are imported from react-router and the other one from react-router-dom and the package versions of those packages don't match. Don't use both of them, read about the difference here.
useHistory won't work in the component where you have your Routes because the context which is needed for useHistory is not yet set.
useHistory will work on any child component or components which you have declared in your Router but it won't work on Router's parent component or Router component itself.
The solution is:
in the Main (father) component
import { BrowserRouter } from "react-router-dom";
<BrowserRouter><App /></BrowserRouter>
in the child component (App)
import { withRouter } from "react-router-dom";
function App(props) {
const { i18n } = useTranslation();
const { language } = useContext(AppContext);
let history = useHistory();
useEffect(() => {
i18n.changeLanguage(language);
}, []);
return(
<Route path="/">
<div className={testClass}>HEADER</div>
</Route>
)
}
export default withRouter(App);
I updated my react-router-dom from 5.0.0 to ^5.1.2 and it's been solved. You may notice that the useHistory is in a sub-component.
Use BrowserRouter.
import {
BrowserRouter as Router,
Route,
Switch,
} from 'react-router-dom';
If you use Router, then you need to specify a history for it:
import {
Router,
Route,
Switch,
} from 'react-router-dom';
// Ensure you destructure the createBrowserHistory object
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
return (
<Router history={history} >
...
</Router>
);
In a short, you should move const history = useHistory(); to your sub-component

Meteor, React Router 4, and Authentication

I've been scouring the inet trying to find anywhere that defines how to handle authentication in meteor and react router 4 .
Basically, I want certain routes to only be available to authenticated users. Is there any documentation on it?
Aseel
Meteor has a very well developed User Accounts system. It provides ready libraries for OAuth authentication with Twitter, Facebook, etc. as well as a basic but useful UI packages. Check Meteor's official guide here first.
For implementing routing you need to track Meteor.userId() and change route via Meteor's reactive system called Tracker. Meteor.userId() returns a userId if currently connected user is logged in, and null otherwise. I provide an example code where React Router is used for routing, below. Notice that you'll will also need the historypackage to be installed and imported while working with React Router v4.
In your client/main.js;
import { Meteor } from 'meteor/meteor';
import React from 'react';
import ReactDOM from 'react-dom';
import { Tracker } from 'meteor/tracker'
import {onAuthChange, routes} from "../imports/routes/routes";
Tracker.autorun(function(){
const authenticated = !! Meteor.userId();
onAuthChange(authenticated);
});
Meteor.startup(() => {
ReactDOM.render(routes, document.getElementById('app'));
});
And in your routes.js file;
import { Meteor } from 'meteor/meteor';
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import createBrowserHistory from 'history/createBrowserHistory'
import Home from './../ui/components/Home';
import Login from './../ui/components/Login';
import NotFound from './../ui/components/NotFound';
import Signup from './../ui/components/Signup';
const history = createBrowserHistory();
const unauthenticatedPages = ['/', '/signup'];
const authenticatedPages = ['/link'];
const publicPage = function () {
if (Meteor.userId()) {
history.replace('/link');
}
};
const privatePage = function () {
if(! Meteor.userId()) {
history.replace('/');
}
};
export const routes = (
<Router history = {history}>
<Switch>
<Route exact path='/:id' component= {Login} onEnter={publicPage}/>
<Route exact path='/signup' component={Signup} onEnter={publicPage}/>
<Route exact path='/link' render={ () => <Home greet='User'/> } onEnter={privatePage} />
<Route component={NotFound}/>
</Switch>
</Router>
);
export const onAuthChange = function (authenticated) {
console.log("isAuthenticated: ", authenticated);
const path = history.location.pathname;
const isUnauthenticatedPage = unauthenticatedPages.includes(path);
const isAuthenticatedPage = authenticatedPages.includes(path);
if (authenticated && isUnauthenticatedPage) { // pages: /signup and /
console.log(`Authenticated user routed to the path /link`);
history.replace('/link');
} else if (!authenticated && isAuthenticatedPage) {
console.log(`Unauthenticated user routed to the path /`);
history.replace('/');
}
};
Here's a neat way to have public routes and authenticated routes:
https://gist.github.com/lucnat/643988451c783a8428a2811dbea3d168
public components are visible by everyone, they use the PublicLayout
authenticated components are visible by authenticated users only -
they use the AuthenticatedLayout
We could have an arbitrary number of layouts. In the example above, there are two layouts - each with it's own navbar.
I've been trying to get a more updated method using functional components.
I've tried implementing a conditional check similar to the documentation of React-router.
This was working after giving history.push to a desired route after waiting for Meteor.loginWithPassword to complete.
But refreshing the browser ended up rendering login page again.
Meteor is having an intermediate state of Meteor.loggingIn().
Handling this state in the Authentication check fixed this issue.
Feel free to give feedback.
I've created a gist with an implementation for authentication of routes in Meteor - React-router stack with functional components and hooks.
Check this gist with basic structure of the implementation.
https://gist.github.com/rinturj84/0ef61005bf3a4ca5fb665dfc5f77e3d1
Actually, the best idea to do that is to create Multiple separated routers because you can take benefits from using Meteor Reactive-var.
This is a sample :
export default function App() {
if (Meteor.user()) {
return (
<React.StrictMode>
<Global_Router Client={null} About={About} HomeNavbar={HomePageNav} HomePage_Home={HomePage_Home}
HomeFooter={Footer} Homepage_Contacts={Homepage_Contacts}/>
</React.StrictMode>
);
}
else {
return(
<RouterClient/>
);
}
Router client
export const RouterClient = () => {
return (
<Router className="container-fluid">
<Switch >
<Route exact path="/Client" >
<HomeCLient/>
</Route>
<Route path="*">
<Redirect to="/Client" />
</Route>
</Switch>
</Router>
)
};
Respectively,you can create a router for the admin too. In general, that is the most efficient way to do that.

Resources