- To start backend
cd backend
node app.js
- To start frontend
cd frontend
npm run start
###Router The documentation can be found https://reactrouter.com/en/main
-
To install router run
npm install react-router-dom
-
Create router/index.js
-
import { createBrowserRouter, } from 'react-router-dom';
-
define the available pages
-
import HomePage from '../pages/Home';
-
const router = createBrowserRouter([ { path: '/', element: 'RootLayout', //Component which has to be rendered as page errorElement: , //Error page if user tpe wrong url children: [ { index: true, // to set default route, that should be loaded when parent route is active // path: '', // '/' - absolute path, thus here we need to use relative path element: // component that should be rendered }, { path: 'products', element: }, { path: 'products/:productId', //:productId - variable for dynamic routes element: } ]
}, {} //represents one route ])
-
-
in App.js
- import { RouterProvider } from 'react-router-dom';
- import router from './router/index';
function App () { return <RouterProvider router={router}/>; }
- in place where we want to display all pages - RootLayout -add
-
To reach the route (navigate) to it
- import { NavLink } from 'react-router-dom';
- <NavLink className={({ isActive }) => { return isActive ? classes.active : undefined;}} //isActive - pass automatically by React to='' //relative path end> // end={true} React will consider the route as active only if it finishes ''(relative pass as mentioned in "to") if end={false} React will consider the route as active if it has '' (relative pass as mentioned in "to") - to style nav link use a:hover, a.active a OR
- import {Link} from 'react-router-dom';
-
Programatically navigate to the pages - To get access to navigation object import {useNavigate} from 'react-router-dom';
const navigate = useNavigate(); navigate('/'); navigate('products')
-
Dynamic routes
- in router path: 'products/:productId',
- in component we need this parameter import { useParams} from 'react-router-dom'; const params = useParams(); productId = params.productId //the same as in router
-
Paths are relative this means that child routes are appended to parent route
-
To go back
Back
-
Loader property to perform the action while navigation to page add loader property to router
-
loader: eventsLoader, //eventsLoader - function which is executed just before the react navigate to the page, as a rule this function is defined at the component/page we need these data
-
at the page the data returned from loader is available import { useRouteLoaderData } from 'react-router-dom'; const {events} =useRouteLoaderData(ID);
OR if it is the direct page with loader
import { useLoaderData } from 'react-router-dom'; const {events} = useLoaderData();
-
to use async and perform few action add
export async function loader () { // React hooks can NOT be used here return defer({ events: await loadEvents() // to execute function which return promise event: await loadEvent(id) ..... });
}
- to ReactRouter will wait till data is fetched
const {events} = useRouteLoaderData('events'); // data that returns from loader
return <Suspense fallback={<p style={{textAlign : 'center'}}>Loading...
}> {loadedEvents => }- it there is error, router will render the closest ErrorElement
- Handling Error if error occurred and new Error is thrown, ReactRouter renders the closest ErrorElement (in router.index) then trow error OR import { json } from 'react-router-dom'; use throw json({message: "Text"}, {status: 500}) if !response.ok
-
-
Loading route indicator It is visible NOT at the page that is loaded but on lower level, which is already rendered (RootLayout) import { useNavigation} from 'react-router-dom'; const navigation = useNavigation(); navigation.state can be 'loading'/'submiting'/'idle' {navigation.state === 'loading' &&
Loading...
} -
To redirect page import { redirect } from 'react-router-dom'; redirect('/events');
-
To send form data
-
add actions in router.js to needed route. This action is as a rule define in the component that need these data
-
import {Form} from 'react-router-dom'; !!!! Form will NOT be sent to BE, but all data will be sent to action in Router
-
all fields has to have field name attribute
-
{request, params} is sent automatically to route action, by clicking inside
-
request contains all form data
-
to get form data => formData = await request.formData();
-
data.get('fieldName');
-
to set error data (for validation) return {validationError : "Error"} to access this error => data.validationError
- to trigger action programatically
- import {useSubmit} from 'react-router-dom'
- const submit = useSubmit();
- submit(DATA, {method: 'delete'}, ROUTE_PATH) - will trigger action, which defined in router, ROUTE_PATH if the action if defined in another route
- to trigger action programatically
-
To handle the response data from the action
- import { useActionData } from 'react-router-dom';
- const data = useActionData();
- data is set when action return some data ether From BackEnd or by validation
-
-
useFetcher
-
import {useFetcher} from 'react-router-dom';
-
const fetcher = useFetcher()
-
fetcher.Form - will still trigger the action, but will not initialize the route transition It means that the action will dispatch without navigation to this page therefore add the action='pathToPage' which action has to be dispatched.
-
const {data, state} = fetcher; to get data of from fetcher
- state - 'idle/loading/submitting'
- use the state to change UI
-
-Defer loading - import { defer, Await } from 'react-router-dom'; - import { Suspense } from 'react'; - make loaderFunction separate function(async func)
- export async function loader () {
// React hooks can NOT be used here
return defer({
events: await loaderFunction() // to execute function which return promise
data: await secondLoaderFunction() // Execute here
});
}
//omit await if we do not nee to wait some data
-We still have access to loaded data const {events} = useRouteLoaderData('events'); OR const {data} = useLoaderData(); (if it is root page)
- return <Await resolve=events>
<Suspense fallback={<Loader/>}> // Is us to to fallback while we fetching the data
{loadedEvents => <EventsList events={loadedEvents}/>} //await will wait till data loaded and will call this func with loadedEvents automatically
</Await>