Symfony and React router, no route found - javascript

I am using Symfony3 and I am creating a bundle using React.js using itself react-router.
The issue is when I use the routing in react, if I reload the page the symfony routing module send 'No Route Found"
My routes are /admin for the index page and /admin/data for the next page.
When I load the page /admin everything is good, I click on the link to go to /admin/data, everything works, react send me dynamically on it, but now when I refresh (F5) the page /admin/data, Symfony intercept it and try to find the routing in its code and redirect to /404 "No Route Found".
I know on AngularJs, the framework is using ancors Path "localhost://admin/#/data", which seems easier to manage but react-router use "localhost://admin/data"
My symfony routing:
admin:
path: /admin
defaults: { _controller: BiBundle:Admin:default }
My React routing:
import { Router, browserHistory } from "react-router";
<Router history={browserHistory}>
<Route path="/admin" component={App}>
<IndexRoute components={{content: DashboardPage}} />
<Route path="data/list"
components={{content: DataListPage}} />
<Route path="*"
components={{content: _ => <h1>Page not found.</h1>}} />
</Route>
</Router>
My link on /admin page:
<Link to={'/admin/data/list'}>Data</Link>
I was thinking to modify my .htaccess to redirect all /admin/* to /admin but seems overkill for that issue.
I am using Apache2 server too.
EDIT
I have replaced browserHistory by hashHistory
import { Router, hashHistory } from "react-router";
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute components={{content: DashboardPage}} />
<Route path="data/list"
components={{content: DataListPage}} />
<Route path="*"
components={{content: _ => <h1>Page not found.</h1>}} />
</Route>
</Router>
It had the result to change my path as it is used in AngularJs (or close enough), so now I have /admin#/ and /admin#/data/list, so symfony always catch /admin and react-router catch #/ or #/admin/data
What do you think ? Is it the good methodology ?

To make your AJAX routing accessible from url directly (i.e. typing /admin/data in browser URL) without being redirected server-side, you need to make your base route (the Symfony route that renders your React application) taking a parameter that will represents your AJAX routing.
To do this, the parameter must allow slashes, example:
admin:
path: /admin/{reactRouting}
defaults: { _controller: BiBundle:Admin:default, reactRouting: null }
requirements:
reactRouting: ".+"
For a more complex routing, you should look at the FOSJsRoutingBundle that could help you.

Related

Import external static liquid.html file into react

I have this below file saved as bbox.liquid.html in my public folder.
File : https://github.com/aws-samples/amazon-sagemaker-ground-truth-task-uis/blob/master/images/bounding-box.liquid.html
My goal is to either import the file as react component or redirect to the page and show it to user.
Method 1. import the file as react component
I tried this all answers, but its not working.
Method 2. redirect to the page
I tried to redirect it using router in app.js, after clicking it I see a empty page.
<Routes>
<Route exact path="/" element={<Home />} />
<Route path="/about" element={<About/>} />
<Route path="/bbox/" element={<Navigate to = {"/bbox.html"} replace />} />
</Routes>
[info] index.tsx:30 No routes matched location "/bbox.html"
Note: once after a reload it shows the expected page.
It would be great I get any working mechanism for method 1

React Router V6 - NotFound component not working with dynamic parameter/slug?

I have installed "react-router-dom": "^6.0.0-beta.0" and created some page routes. Facing problems where the Page404 / NotFound component is not working if a page doesn't exist. For some reason when I am using dynamic page/post slug the component NotFound will not work if there is no page/post with this ID.
Is there an option inside React Router which solves this issue?
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import AllPosts from "components/AllPosts";
import SinglePost from "components/SinglePost";
import NotFound from "components/Page404";
const App = () => (
<Router>
<Routes>
<Route element={<AllPosts />} path="/" exact />
<Route element={<SinglePost />} path="/:slug" />
<Route element={<NotFound />} path="*" />
</Routes>
</Router>
);
export default App;
The Routes and Route component can't possibly know ahead of time that some dynamic path, "/someUnsupportedIdValue" for example, isn't a valid path to be handled by SinglePost.
The options you have here are:
Conditionally render some alternative UI in SinglePost, something along the lines of "A page by this ID isn't found".
Check if a page with matching ID exists, conditionally render that page, or a redirect (Navigate component replaced Redirect in v6) to your more generic 404 page (actually, a redirect to any "throw away" path that isn't explicitly handled already will land you on your 404 page). Or you can imperatively redirect with a navigate(to, { replace: true }).
Try to remove exact because was removed from v6 and make sure Page404 is the correct component or create Notfound.jsx
Check if the post not exists then redirect to Notfound page.

How to handle front-end and back-end paths on browser refresh

I'm using React, React-router and Play Framework to serve and render an application.
This is what my Routes.jsx looks like:
const Routes = (
<Route path="/">
<Route component={App}>
<Route path="attributes/:itemId" component={AttributesContainer}/>
<IndexRoute component={ItemsContainer}/>
</Route>
</Route>
);
export default Routes
As you can see, path /attributes/:itemId renders a component called AttributesContainer.
This path is called from ItemsContainer in this function:
_onClickAttributes(itemId) {
browserHistory.push({pathname: '/attributes/' + itemId});
}
Everything works just fine there. But if I refresh the browser while in /attributes/:itemId, back-end returns
Action Not Found
For request 'GET /attributes/5'
instead of the front end component. I understand the browser is doing a get request and that's why I get this message.
So, what's the best technique to handle this?

How to use React Router with Electron?

Using this boilerplate as reference I created an Electron app. It uses webpack to bundle the scripts and express server to host it.
Webpack config is practically same as this and server this.
Electron's script loads:
mainWindow.loadURL('file://' + __dirname + '/app/index.html');
And index.html loads the script hosted by the server:
<script src="http://localhost:3000/dist/bundle.js"></script>
I run electron index.js to build the app and node server to start server which using webpack bundles the scripts.
It works fine, my React component App is mounted. But how I integrate react-router into this?
I implemented it the same way I would in a browser app. I get this error:
[react-router] Location "/Users/arjun/Documents/Github/electron-app/app/index.html" did not match any routes
It is taking file path as the route. Going through the boiler plate code did not help. What am I missing?
Had to Replace BrowserRouter with HashRouter.
import {
HashRouter,
Route
} from "react-router-dom";
And then in my index.js or the entry file of the Electron app I had something like this:
<HashRouter>
<div>
<Route path="/" exact component={ Home } />
<Route path="/firstPage" component={ FirstPage } />
<Route path="/secondPage" component={ SecondPage } />
</div>
</HashRouter>
And then everything just worked.
The reasoning: BrowserRouter is meant for request-based environments whereas HashRouter is meant for file-based environments.
Read more here:
https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/api/HashRouter.md
Another option would be to use hashHistory instead. Actually, in your referenced repo you can see that they're using hashHistory, how about trying that and posting back?
I'm using React Router v4 and didn't want to fallback to the HashRouter, so I solved it with something amongst the likes of:
import { Redirect, BrowserRouter } from 'react-router-dom';
const App = () => (
<BrowserRouter>
<div>
{window.location.pathname.includes('index.html') && <Redirect to="/" />}
</div>
</BrowserRouter>
);
Best option at the time of this answer is to use the MemoryRouter, worked for me :)
What about simply using Switch to default to "/" as follows:
<Switch>
<Route path="/" exact component={Home}/>
<Route path="/foo" component={Foo}/>
<Route path="/bar" component={Bar}/>
<Route render={() => <Redirect to="/"/>}/>
</Switch>
This way, "/index.html" will redirect to "/"
The (current) react-router docs say:
Generally speaking, you should use a <BrowserRouter> if you have a server that responds to requests and a <HashRouter> if you are using a static file server.
An Electron app is basically a static file server.
MemoryRouter can also work, so long as all routing originates from within the React part of the app. It only falls down when you want to navigate to a specific page from the Browser process, e.g. you want to pop up a new window and navigate directly to a "General Preferences" page. In that case, you can do this with HashRouter:
prefsWindow.loadURL(`file://${__dirname}/app/index.html#/general-prefs`);
I don't think there is a way to do that with MemoryRouter (from the Browser process).
Agree with Niekert.
But I believe it is better to handle like this before any route management.
if ( window.location.pathname.includes('index.html') ) {
location.pathname = ROUTES.ROOT;
}
It all depends on what kind of URL you pass to mainWindow.loadURL.
file://...
If you load index.html directly through the file:// protocol, such as
mainWindow.loadURL('file://' + path.join(__dirname, '../index.html#/home'))
then you need to use HashRouter:
<HashRouter>
<Routes>
<Route path='/home' element={<MyHomeScreen/>}>
</Routes>
</HashRouter>
Note that the # in index.html#/home is very important!
Why?
Think about what would happen if you wrote index.html/home. Your computer would try to retrieve a home file inside an index.html directory. The # prevents this, and thus we need to use HashRouter.
http://localhost:3000
If you load index.html from a server such as localhost:3000, then you have two options:
include the #, as in
mainWindow.loadURL('http://localhost:3000#/home')
and use HashRouter exactly as above,
OR
don't include the #, as in
mainWindow.loadURL('http://localhost:3000/home')
and use BrowserRouter like this:
<BrowserRouter>
<Routes>
<Route path='/home' element={<MyHomeScreen/>}>
</Routes>
</BrowserRouter>
Many people prefer to use BrowserRouter in this case because it avoids complicating the URL with a #.
In your main process:
mainWindow.loadURL(resolveHtmlPath('index.html'));
In your renderer process:
import { HashRouter as Router, Routes, Route } from 'react-router-dom';
//...
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/search" element={<Search />} />
<Route
path="/library"
element={<Library />}
/>
</Routes>
</Router>
The call to resolveHtmlPath removed the need for using hashtags for me. Using a BrowserRouter out of the box gave me the warning message in dev tools.
This function is in the Electron React Boilerplate project that you referenced:
import { URL } from 'url';
import path from 'path';
export function resolveHtmlPath(htmlFileName: string) {
if (process.env.NODE_ENV === 'development') {
const port = process.env.PORT || 1212;
const url = new URL(`http://localhost:${port}`);
url.pathname = htmlFileName;
return url.href;
}
return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}`;
}

React-router: allow undefined routes to pass to server

My stack: Django app with React/react-router/flux frontend.
I'm managing some static pages (plus 404 page, etc) server-side, and want to configure my router to pass any undefined routes through to the server.
Here's how things are set up now:
let routes = (
<Route name="app" path="/" handler={ App }>
<Route name="register" handler={ Register }/>
<Route name="login" handler={ Login }/>
<Route name="refer" handler={ Refer }/>
<Route name="help" handler= { Help }/>
<Route name="list-property" handler= { ListProperty }/>
<DefaultRoute handler={ Home }/>
</Route>
);
router = Router.create({ routes, location });
router.run((Handler, state) => {
React.render(<Handler {...state} />, rootEl);
});
mysite.com/register will get routed through the react router to my Register page component, but I want mysite.com/thanks to hit my server (so django can manage the route). Right now I get a blank page.
I'm perusing the documentation here but can't find what I need: http://rackt.github.io/react-router/#NotFoundRoute
Maybe I'm overlooking something... thanks!
If you want certain paths to hit the server redirect to those paths using a standard anchor redirect or similar rather than use the Router.Link to navigate.

Categories

Resources