I want to link a local file description.js which is in the same folder. How can I link it to this file? The purpose is to open that file as a page when the user clicks on read more button.
import React, { Component } from 'react';
import image from './images/pk.png';
//import Description from './description';
<script type="text/javascript" src="description.js"></script>
export default class Box extends Component {
render() {
let {name,code,numCode,amb,fire,pol,dispatch}=this.props;
return (
<div className='box'>
<div className='e_body'>
<img className="countryImg" src={image} alt='Fail to load'/>
<h5>{name}</h5>
<p>ISO-Code: {code}<br/>ISO-Numeric: {numCode}</p>
<a href="description.js" className='btn btn-sm btn-warning'>Read More</a>
</div>
</div>
)
}
}
first define routes in App.js
and rename your file with capital description.js -> Description.js
App.js should look like:
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
const App = ({}) => {
const navigate = useNavigate();
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Your Home Compoenent />} />
<Route path="/description" element={<Description />} />
</Routes>
</BrowserRouter>
);
};
Your component
import React, { Component } from "react";
import image from "./images/pk.png";
import { useNavigate } from "react-router-dom";
const Box = ({ name, code, numCode, amb, fire, pol, dispatch }) => {
const navigate = useNavigate();
return (
<div className="box">
<div className="e_body">
<img className="countryImg" src={image} alt="Fail to load" />
<h5>{name}</h5>
<p>
ISO-Code: {code}
<br />
ISO-Numeric: {numCode}
</p>
<button
className="btn btn-sm btn-warning"
onClick={() => {
navigate("/description");
}}
>
Read More
</button>
</div>
</div>
);
};
You have to use 'Routes' for this .
then do
import Usenavigate from react-router-dom
const navigate = useNavigate();
inside onClick callback function
navigate('/Description')
Related
I am trying to protect certain routes so only users who have authenticated can be redirected and have access to the app page but the redirect does not work, and neither does the page load. When I navigate to the localhost:7171/app page it shows a Whitelabel Error Page
App.js
import React from "react";
import { ReactKeycloakProvider } from "#react-keycloak/web";
import keycloak from "./Keycloak";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Nav from "./components/Nav";
import WelcomePage from "./pages/Homepage";
import SecuredPage from "./pages/Securedpage";
import PrivateRoute from "./helpers/PrivateRoute";
function App() {
return (
<div>
<ReactKeycloakProvider authClient={keycloak}>
<Nav />
<BrowserRouter>
<Routes>
<Route exact path="/" element={<WelcomePage />} />
<Route path="/app"
element={<PrivateRoute>
<SecuredPage />
</PrivateRoute>}/>
</Routes>
</BrowserRouter>
</ReactKeycloakProvider>
</div>
);
}
export default App;
Securedpage.js
import React from 'react';
const Secured = () => {
return (
<div>
<h1 className="text-black text-4xl">Welcome to the Protected Page.</h1>
</div>
);
};
export default Secured;
PrivateRoute.js (the log is not hit ever)
import { useKeycloak } from "#react-keycloak/web";
const PrivateRoute = ({ children }) => {
const { keycloak } = useKeycloak();
const isLoggedIn = keycloak.authenticated;
console.log("checking auth access " + isLoggedIn);
return isLoggedIn ? children : null;
};
export default PrivateRoute;
Nav.js
import React from "react";
import { useKeycloak } from "#react-keycloak/web";
const Nav = () => {
const { keycloak, initialized } = useKeycloak();
function loginHelper(){
console.log("login clicked");
keycloak.login();
};
function logoutHelper(){
console.log("login clicked");
keycloak.logout();
};
return (
<div>
<div>
<section>
<nav >
<div >
<h1>
Home Page.
</h1>
<ul>
<li>
<a href="/">
Home
</a>
</li>
{/* <li>
// <a className="hover:text-blue-800" href="/secured">
// Secured Page
// </a>
// </li>-*/}
</ul>
<div>
<div>
{!keycloak.authenticated && (
<button
type="button"
className="text-blue-800"
onClick={() => loginHelper()}
>
Login
</button>
)}
{!!keycloak.authenticated && (
<button
type="button"
className="text-blue-800"
onClick={() => logoutHelper()}
>
Logout ({keycloak.tokenParsed.preferred_username})
</button>
)}
</div>
</div>
</div>
</nav>
</section>
</div>
</div>
);
};
export default Nav;
Two problems:
After login, it does not redirect to /app page. I have added /app/* as a redirect URI in keycloak setting.
Even if I manually go to /app page, it shows an error instead of redirecting to the login page.
I have two buttons on my react app's header. One for translating the application to Spanish and the other for English. The problem is that every time I press one of this buttons and update the state, the homepage gets loaded despite the translation is completed correctly. How can I avoid this redirection to the homepage and remain in the current page where the user is at that moment?
App.js, where the IntlProvider gets the language through state triggered by onclick function:
import { MsalProvider } from "#azure/msal-react";
import "bootstrap/dist/css/bootstrap.min.css";
import { IntlProvider } from "react-intl";
import { BrowserRouter } from "react-router-dom";
import "./App.css";
import AppContent from "./AppContent";
import { lang } from "./assets/lang/lang";
import Header from "./pages/common/Header";
import { useState } from "react";
function App({ msalInstance }) {
const [localeLanguage, setLocaleLanguage] = useState("en");
const onChangeLanguage = (lang) => {
setLocaleLanguage(lang);
};
return (
<MsalProvider instance={msalInstance}>
<BrowserRouter>
<IntlProvider
key={localeLanguage}
locale={localeLanguage}
messages={lang[localeLanguage]}
>
<Header onChangeLanguage={onChangeLanguage} />
<AppContent />
</IntlProvider>
</BrowserRouter>
</MsalProvider>
);
}
export default App;
Header.js, where the two buttons are:
import { useIsAuthenticated, useMsal } from "#azure/msal-react";
import { FormattedMessage } from "react-intl";
import { Link } from "react-router-dom";
import logo from "../../assets/img/softwareOne.png";
import { loginRequest } from "../../util/authConfig";
import { useIntl } from "react-intl";
export default function Header(props) {
const isAuthenticated = useIsAuthenticated();
const { instance } = useMsal();
const intl = useIntl();
return (
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<Link className="navbar-brand" to="/">
<img src={logo} className="logo-navbar" alt="" />
</Link>
<div className="collapse navbar-collapse text-center">
<span className="navbar-text">
<FormattedMessage id="well_architected_survey" />
</span>
</div>
<div className="flex">
<button
className="btn btn-secondary"
onClick={() => {
props.onChangeLanguage("es");
}}
value="es"
>
{intl.locale === "es" ? "Español" : "Spanish"}
</button>
<button
className="btn btn-secondary m-3"
onClick={() => {
props.onChangeLanguage("en");
}}
value="en"
>
{intl.locale === "en" ? "English" : "Inglés"}
</button>
</div>
<div>
<button
className="btn btn-outline-secondary logout-header"
onClick={() =>
isAuthenticated
? instance.logoutRedirect({ postLogoutRedirectUri: "/" })
: instance.loginRedirect(loginRequest)
}
>
<FormattedMessage
id={isAuthenticated ? "logout_button" : "login_button"}
/>
</button>
</div>
</nav>
);
}
I see that the localeLanguage state is used as a React key on the IntlProvider component. When the key value changes this will necessarily remount that component and its entire React subtree (which may very well include any initial mounting effects in any rendered children components). I don't see a point of using a React key here though so it's likely safe to remove it.
function App({ msalInstance }) {
const [localeLanguage, setLocaleLanguage] = useState("en");
const onChangeLanguage = (lang) => {
setLocaleLanguage(lang);
};
return (
<MsalProvider instance={msalInstance}>
<BrowserRouter>
<IntlProvider // <-- remove key prop
locale={localeLanguage}
messages={lang[localeLanguage]}
>
<Header onChangeLanguage={onChangeLanguage} />
<AppContent />
</IntlProvider>
</BrowserRouter>
</MsalProvider>
);
}
I'm creating a page, like Amazon. In the index page, I have a list of products, and when the user clicks the link it goes to the product page that has all the details of the product, but for me to create this page I've to get the ID from the product but I can't get it.
App.js:
<main className="main">
<div className="content">
<Routes>
<Route path="/product/:id" element={<ProductScreen />} />
<Route path="/" exact element={<HomeScreen />} />
</Routes>
</div>
</main>
HomeScreen:
import React from 'react';
import data from "../data";
import { Link } from 'react-router-dom';
function HomeScreen(props) {
return (
<ul className="products">
{
data.products.map(product =>
<li>
<div className="product">
<Link to={'/product/' + product._id}>
<img
src={product.image}
alt="Product"
className="product-image"
/>
</Link>
<div className="product-name">
<Link to={'/product/' + product._id}>{product.name}</Link>
</div>
<div className="product-brand">{product.brand}</div>
<div className="product-price">{product.price}</div>
<div className="product-rating">{product.rating} Leafs ({product.numberReviews} Reviews)</div>
</div>
</li>
)
}
</ul>
);
}
export default HomeScreen;
ProductScreen:
import React from 'react';
import data from '../data';
function ProductScreen(props) {
console.log(props.match.params.id)
return <div>Product Screen</div>
}
export default ProductScreen;
I console.log it to see if everything was okay but the error shown is
TypeError: Cannot read properties of undefined (reading 'params')
What am I missing? I tried several kinds of stuff that I saw on the web.
You need to use useParams hook from React Router Dom. Like below:
import React from 'react';
import data from '../data';
import {useParams} from "react-router-dom"
function ProductScreen(props) {
const {id} = useParams();
console.log(id)
return <div>Product Screen</div>
}
export default ProductScreen;
After setting /product/:id router as you did:
<Route path="/product/:id" element={<ProductScreen />} />
For those who got no result, try this:
import React from 'react';
import data from '../data';
import {useParams} from "react-router-dom"
function ProductScreen(props) {
const params = useParams();
const id = params.id
console.log(id)
return <div>Product Screen</div>
}
export default ProductScreen;
I've built a react front end for my rest api. I've got them both deployed! However my navbar component has tags and do not work after clicking on them once. This happens in both netlify and gh-pages. Has anyone encountered this solution before? I am using HashRouter instead of ReactRouter. Thanks for taking your time with this :)
import React from "react";
import { Link } from "react-router-dom";
export default ({ context }) => {
const authedUser = context.authenticatedUser;
//Nav bar conditionally rendered on if the user is logged in or not
return (
<div>
<div className="header-div">
<div>
<Link to="/" className="header-div-left">
Student Courses
</Link>
</div>
<nav>
{authedUser ? (
<React.Fragment>
<div className="header-div-right">
<span className="header-div-right">
Welcome {authedUser.firstName} {authedUser.lastName}
</span>
<Link className="header-div-right" to="/signout">
Sign Out
</Link>
</div>
</React.Fragment>
) : (
<React.Fragment>
<div className="header-div-right-up-in">
<Link className="header-div-right" to="/signup">
Sign Up
</Link>
<Link className="header-div-right" to="/signin">
Sign In
</Link>
</div>
</React.Fragment>
)}
</nav>
</div>
</div>
);
};
import React from 'react';
import {
HashRouter as Router,
Route,
Switch
} from 'react-router-dom';
import './App.css';
import CourseDetail from './components/CourseDetail';
import Courses from './components/Courses';
import CreateCourse from './components/CreateCourse';
import Header from './components/Header';
import UpdateCourse from './components/UpdateCourse';
import UserSignIn from './components/UserSignIn';
import UserSignOut from './components/UserSignOut';
import UserSignUp from './components/UserSignUp';
import NotFound from './components/NotFound';
import PrivateRoute from './PrivateRoute';
import withContext from './Context';
//Connecting the SignUp & SignIn to context.
//This shares the data and actions throughout the component tree
/* Adding the const's as the component to the route handler
lets the components UserSignIn & UserSignUp gain access to
the function in context and any data or actions passed into
<Context.Provider value={value}> */
const UserSignInWithContext = withContext(UserSignIn);
const UserSignUpWithContext = withContext(UserSignUp);
const UserSignOutWithContext = withContext(UserSignOut);
/* To let the user know they are signed in
need to make changes to the name display in the end header */
const HeaderWithContext = withContext(Header);
const CoursesWithContext = withContext(Courses);
const CourseDetailsWithContext = withContext(CourseDetail);
const UpdateCourseWithContext = withContext(UpdateCourse)
const CreateCourseWithContext = withContext(CreateCourse)
export default () => (
<Router>
<div >
<HeaderWithContext/>
<Switch>
<Route exact path="/" component={CoursesWithContext} />
<PrivateRoute path="/courses/create" component={CreateCourseWithContext} />
<Route exact path="/courses/:id" component={CourseDetailsWithContext} />
<PrivateRoute path="/courses/:id/update" component={UpdateCourseWithContext} />
<Route path="/signin" component={UserSignInWithContext} />
<Route path="/signup" component={UserSignUpWithContext} />
<Route path="/signout" component={UserSignOutWithContext} />
<Route component={NotFound} />
</Switch >
</div >
</Router>
);
I'm new in React and doesn't know how to create List and Detail view using React Router DOM. Some how I created it but I know this is not a good way to do it. If you look into below code, you will find it will always reload the whole page if I select another campaign. What will be the good way to do it. Please help...
App.js
<Switch>
<Fragment>
<PrivateRoute exact path="/admin/campaigns/:id" component={CampaignComponent}/>
<PrivateRoute exact path="/admin/campaigns/:id/messages" component={CampaignComponent}/>
<PrivateRoute exact path="/admin/campaigns/:id/contacts" component={CampaignComponent}/>
</Fragment>
</Switch>
Campaign.js
let layout;
switch (props.match.path) {
case '/admin/campaigns/:id':
layout = <CampaignDetailComponent props={props}/>;
break;
case '/admin/campaigns/:id/messages':
layout = <CampaignMessageListComponent props={props}/>;
break;
case '/admin/campaigns/:id/contacts':
layout = <CampaignContactListComponent props={props}/>;
break;
default:
layout = <div/>;
}
return (
<div>
<div className="col-6">
<CampaignListComponent props={props}/>
</div>
<div className="col-6">
{layout}
</div>
</div>
)
So, in the first col-6 I want to show the list of Campaigns and in second col-6 I want to render the components as per route change.
You can follow this link to see the actual working code sample that demonstrate this issue.
Issue
You have your "navigation" coupled to your page UI.
Solution
Split out the rendering of your links in the left section from the content in the right section. The rest of the changes a centered around computing paths and route structuring.
App.js
Render the campaign list container and navigation on its own route. This is so the nested links can inherit from the route path.
import React, { Component } from "react";
import { HashRouter, Redirect, Route, Switch } from "react-router-dom";
import CampaignComponent from "./Campaign/Campaign";
import CampaignListComponent from "./Campaign/Components/CampaignList";
import "./styles.css";
class App extends Component {
render() {
return (
<div className="App">
<h3>Sample app to demonstrate React Router issue</h3>
<HashRouter>
<div className="campaign-container">
<div className="campaign-list">
<Route path="/admin/campaigns">
<CampaignListComponent />
</Route>
</div>
<div className="campaign-detail">
<Switch>
<Route path="/admin/campaigns" component={CampaignComponent} />
<Redirect from="*" to="/admin/campaigns" />
</Switch>
</div>
</div>
</HashRouter>
</div>
);
}
}
Campaign list component
import React, { useState } from "react";
import { Link, generatePath, useRouteMatch } from "react-router-dom";
const CampaignListComponent = () => {
const [campaignList, setCampaignList] = useState([
{ id: 1, name: "Campaign1" },
{ id: 2, name: "Campaign2" },
{ id: 3, name: "Campaign3" },
{ id: 4, name: "Campaign4" },
{ id: 5, name: "Campaign5" }
]);
const { url } = useRouteMatch();
return (
<div style={{ width: "90%" }}>
{campaignList.map(({ id, name }) => (
<div className="campaign-list-item" key={id}>
<Link to={generatePath(`${url}/:id`, { id })}>{name}</Link>
</div>
))}
</div>
);
};
Campaign component
import React from "react";
import { Route, Switch, useRouteMatch } from "react-router-dom";
import CampaignMessageListComponent from "./Components/CampaignMessageList";
import CampaignDetailComponent from "./Components/CampaignDetail";
import CampaignContactListComponent from "./Components/CampaignContactList";
const CampaignComponent = () => {
const { path } = useRouteMatch();
return (
<div className="campaign-list">
<Switch>
<Route
path={`${path}/:id/messages`}
component={CampaignMessageListComponent}
/>
<Route
path={`${path}/:id/contacts`}
component={CampaignContactListComponent}
/>
<Route path={`${path}/:id`} component={CampaignDetailComponent} />
</Switch>
</div>
);
};
Content components
Contact
import React from "react";
import { useHistory } from "react-router-dom";
const CampaignContactListComponent = () => {
const history = useHistory();
return (
<div className="row">
<p>Campaign Contact List</p>
<button onClick={history.goBack}>Go Back</button>
</div>
);
};
Message
import React from "react";
import { useHistory } from "react-router-dom";
const CampaignMessageListComponent = () => {
const history = useHistory();
return (
<div className="row">
<p>Campaign Message List</p>
<button onClick={history.goBack}>Go Back</button>
</div>
);
};
Detail
import React from "react";
import { Link, useHistory, useParams, useRouteMatch } from "react-router-dom";
const CampaignDetailComponent = () => {
const { id } = useParams();
const { url } = useRouteMatch();
const history = useHistory();
return (
<div>
<h6>Campaign Detail</h6>
<p>You have selected Campaign - {id}</p>
<button>
<Link to={`${url}/messages`}>Goto Messages</Link>
</button>
<button>
<Link to={`${url}/contacts`}>Goto Contacts</Link>
</button>
<button onClick={history.goBack}>Go Back</button>
</div>
);
};