can't route successfully between components in react app - reactjs

I have a static react app (that means there is not server side rendering) located under example.com/web-class.gr. My problem is that I can't route between components when I use my sidebar menu.
For instance. When I navigate to example.com/web-class.gr/css-intermediate the page loads as expected. From now on if I navigate to different lessonName the page is loading as expected. But I also have exercises, which I can't load when I press the corresponding button in my menu. To get an idea this is my index.js file:
import React from 'react';
import { Link as ReactLink } from 'react-router';
import sidebarStore from './Sidebar/SidebarStore';
import lessonValues from '../../lessonValues';
import LessonStore from '../../LessonStore';
import SidebarLink from './Sidebar/SidebarLink';
export default class Sidebar extends React.Component {
constructor() {
super();
this.state = {
SidebarIsCollapse: sidebarStore.getCurrentState()
}
this.NavMdPlaceholderClass = 'hidden-xs col-sm-4 col-md-3 col-lg-3';
}
componentWillMount() {
sidebarStore.on('change', () => {
this.setState({ SidebarIsCollapse: sidebarStore.getCurrentState() });
this.ChangeSidebarState();
});
this.RenderMainMenu();
}
ChangeSidebarState() {
const NAV_DefaultClasses = "col-sm-4 col-md-3 col-lg-3 ";
if (this.state.SidebarIsCollapse) {
this.NavMdPlaceholderClass = NAV_DefaultClasses + "slideInLeft";
} else {
this.NavMdPlaceholderClass = NAV_DefaultClasses + "slideOffLeft";
}
}
RenderMainMenu() {
this.main_menu = [];
for (let link of lessonValues) {
let { Id, url, isExercise, title } = link;
this.main_menu.push(<SidebarLink key={Id} url={url} isExercise={isExercise} title={title}/>);
}
}
render() {
return (
<div class={this.NavMdPlaceholderClass} id="nav-md-placeholder">
<nav id="sidebar">
<ul id="main-menu">
<li class="ripple-btn">
<ReactLink to="/" onClick={this.SetLessonDetails.bind(this)}>
<span class="item-align-fix">
<i class="glyphicon glyphicon-home" style={{'marginRight': '10px'}}></i>
<strong>
<span>AΡΧΙΚΗ</span>
</strong>
</span>
</ReactLink>
</li>
{this.main_menu}
</ul>
</nav>
</div>
);
}
}
here is the SidebarLink component file:
import React from 'react';
import LessonStore from '../../../LessonStore';
import { Link as ReactLink } from 'react-router';
export default class SidebarLink extends React.Component {
SetPageTitle() {
LessonStore.setLesson(this.props.url);
}
render() {
let glyphoconType = 'glyphicon ';
glyphoconType += this.props.isExercise ? 'glyphicon-pencil' : 'glyphicon-ok-sign';
glyphoconType += ' nav-ico untaken-lesson';
return (
<li class="ripple-btn">
<ReactLink to={this.props.url} onClick={() => this.SetPageTitle()} >
<span class="item-align-fix">
<i class={glyphoconType}></i>
<span>{this.props.title}</span>
</span>
</ReactLink>
</li>
);
}
}
But if I refresh the page manually, I am able to reveal the exercise page. But now I can't navigate to any other element. Only if I click it in sidebar menu and manually refresh the page.
To sum up:
The lessons are loading dynamically. I can navigate between them.
I can't navigate to exercises. Only if I click the corresponding exercise and hit the refresh button.
If I'm viewing an exercise (eg exercise-1), I am not able to navigate to any other component.
I use nginx and below is my rule for the project:
location ^~ /web-class.gr/ {
try_files $uri $uri/ =404;
if (!-e $request_filename){
rewrite ^(.*)$ /web-class.gr/index.html break;
}
}
And lastly here is my sidebar component:
import React from 'react';
import { Link as ReactLink } from 'react-router';
import sidebarStore from './Sidebar/SidebarStore';
import lessonValues from '../../lessonValues';
import LessonStore from '../../LessonStore';
import SidebarLink from './Sidebar/SidebarLink';
// some other helper functions here
render() {
return (
<div class={this.NavMdPlaceholderClass} id="nav-md-placeholder">
<nav id="sidebar">
<ul id="main-menu">
<li class="ripple-btn">
<ReactLink to="/web-class.gr/" onClick={this.SetLessonDetails.bind(this)}>
<span class="item-align-fix">
<i class="glyphicon glyphicon-home" style={{'marginRight': '10px'}}></i>
<strong>
<span>AΡΧΙΚΗ</span>
</strong>
</span>
</ReactLink>
</li>
{this.main_menu}
</ul>
</nav>
</div>
);
Is there any problem with ReactLink to? On my apache machine all works as expected. I can't figure out why my program breaks.
Update
I provide the link of the site to help your job become easier. The site is in greek although I believe you can understand it's structure.
web-class.gr
Code on Github

This One worked For me
NB
for React Router
use <BrowserRouter> tag only once to enclose the whole of your application.
Use this tag at the point of Rendering.
For Example
If you are using Create-React-app .Use this at your Index.js file
ReactDom.Render(<BrowserRouter><App/></BrowserRouter>)

Second Update:
Change your render code in react/index.js to
ReactDom.render(
<Router history={browserHistory} >
<Route path="/" component={Layout} >
<IndexRoute component={Index} ></IndexRoute>
<Route path="/exercise-1" name="exercise-1" component={Exercise1} ></Route>
<Route path="/exercise-2" name="exercise-2" component={Exercise2} ></Route>
<Route path="/exercise-3" name="exercise-3" component={Exercise3} ></Route>
<Route path="/exercise-4" name="exercise-4" component={Exercise4} ></Route>
<Route path="/exercise-5" name="exercise-5" component={Exercise5} ></Route>
<Route path="/exercise-6" name="exercise-6" component={Exercise6} ></Route>
<Route path="/:lessonName" name="lesson" component={Lesson} ></Route>
<Route path=":lessonName" name="lesson" component={Lesson} ></Route>
</Route>
</Router>
,app);
i..e the path starts with /

Related

React useTranslation alternative in Class Component

I am a total beginner in React (as I am in StackOverflow, sorry if the form of my post isn't quite right)
I have this SPA app that translates my content from french to english and back, works perfectly fine, but I would like to add an "active" className to my language toggle buttons so I can underline the active language in css, and what I found I had to do was dealing with the state of the component. Now I use a function component with useTranslation, and if I try and convert my function component to a class component, it says useTranslation can't be used in a class component.
Could any of you help me re-write my component so I can make it a class component and use a constructor and deal with the states, but still use the same hooks and functions I'm using now for translation?
I found previous aswers using withTranslation wrapper, but no example that would take my toggle buttons and changeLanguage function for navigation into account, just for {t} plain strings, so I'im a bit lost on how to write this correctly...
Here is my app code as a function component:
import React, { Component } from "react";
import {
Route,
NavLink,
HashRouter
} from "react-router-dom";
import Home from "./Home";
import Projets from "./Projets";
import Contact from "./Contact";
import Design from "./Design";
import Web from "./Web";
import ReactDOM from "react-dom";
import { useTranslation, Trans } from "react-i18next";
export default function App() {
const { t, i18n } = useTranslation();
const changeLanguage = lng => {
i18n.changeLanguage(lng);
};
return (
<div className="App">
<div className="App-header">
<h1>{t("Bienvenue sur notre Blog")}</h1>
</div>
<HashRouter>
<div className="main-container">
<div className="navigation">
<ul className="nav-list">
<li className="nav-links"><NavLink exact to="/"><Trans>Accueil</Trans></NavLink></li>
<li className="nav-links"><NavLink to="/projets"><Trans>Projets</Trans></NavLink></li>
<ul className="nav-sublist">
<li className="nav-sublinks"><NavLink to="/projets/graphisme-maquettes"><Trans>Graphisme</Trans></NavLink></li>
<li className="nav-sublinks"><NavLink to="/projets/web"><Trans>Web</Trans></NavLink></li>
</ul>
<li className="nav-links"><NavLink to="/contact"><Trans>Contact</Trans></NavLink></li>
</ul>
<div class='langSelect'>
<button onClick={() => changeLanguage("fr")} class='langBtn' value='lang'>fr</button>
<button onClick={() => changeLanguage("en")} class='langBtn' value='lang'>en</button>
</div>
</div>
<div className="content">
<Route exact path="/" component={Home}/>
<Route path="/projets" component={Projets}/>
<Route path="/projets/graphisme-maquettes" component={Design}/>
<Route path="/projets/web" component={Web}/>
<Route path="/contact" component={Contact}/>
</div>
</div>
</HashRouter>
</div>
);
}
And here is my i18n.js file:
import i18n from "i18next";
// import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
i18n
// .use(LanguageDetector)
.use(initReactI18next)
.use(LanguageDetector)
.init({
// we init with resources
resources: {
en: {
translations: {
Accueil:"Home",
Projets:"Work",
Graphisme:"Design",
Web: "Web",
Contact:"Contact",
// "Projets":"Work",
"Bienvenue sur notre Blog":"Welcome to our Blog"
}
},
fr: {
translations: {
Accueil:"Accueil",
Projets:"Projets",
Graphisme:"Graphisme",
Web: "Web",
Contact:"Contact",
// "Projets":"Projets",
"Bienvenue sur notre Blog":"Bienvenue sur notre Blog"
}
}
},
fallbackLng: "fr",
debug: true,
// have a common namespace used around the full app
ns: ["translations"],
defaultNS: "translations",
keySeparator: false, // we use content as keys
interpolation: {
escapeValue: false
}
});
export default i18n;
Now, what I would like to achieve is something like this:
import React, { Component } from "react";
import {
Route,
NavLink,
HashRouter
} from "react-router-dom";
import Home from "./Home";
import Projets from "./Projets";
import Contact from "./Contact";
import Design from "./Design";
import Web from "./Web";
import ReactDOM from "react-dom";
import { useTranslation, Trans } from "react-i18next";
class App extends Component {
constructor(){
super();
this.state = {
underline: false
}
}
render {
const { t, i18n } = useTranslation(); => OBVIOULSY USE SOMETHING ELSE
const changeLanguage = lng => {
i18n.changeLanguage(lng);
}; => ADD/REMOVE THE CLASSNAME HERE AT THE SAME TIME I CHANGE LANGUAGE?
return (
<div className="App">
<div className="App-header">
<h1>{t("Bienvenue sur notre Blog")}</h1>
</div>
<HashRouter>
<div className="main-container">
<div className="navigation">
<ul className="nav-list">
<li className="nav-links"><NavLink exact to="/"><Trans>Accueil</Trans></NavLink></li>
<li className="nav-links"><NavLink to="/projets"><Trans>Projets</Trans></NavLink></li>
<ul className="nav-sublist">
<li className="nav-sublinks"><NavLink to="/projets/graphisme-maquettes"><Trans>Graphisme</Trans></NavLink></li>
<li className="nav-sublinks"><NavLink to="/projets/web"><Trans>Web</Trans></NavLink></li>
</ul>
<li className="nav-links"><NavLink to="/contact"><Trans>Contact</Trans></NavLink></li>
</ul>
<div class='langSelect'>
<button onClick={() => changeLanguage("fr")} class='langBtn' value='lang'>fr</button>
<button onClick={() => changeLanguage("en")} class='langBtn' value='lang'>en</button>
</div>
</div>
<div className="content">
<Route exact path="/" component={Home}/>
<Route path="/projets" component={Projets}/>
<Route path="/projets/graphisme-maquettes" component={Design}/>
<Route path="/projets/web" component={Web}/>
<Route path="/contact" component={Contact}/>
</div>
</div>
</HashRouter>
</div>
);
}
}
export default App;
Thanks in advance, I hope you have everything your need, I really "just" need guidance in how to write all of this without changing the way it works so much, I hope it's actually doable...

Render a new page on react-routing but it renders it inside the current page

This displays a card component that the user sees if the user clicks the <Link>read</Link> it should re-render a new page.
import React from "react";
import { Button } from "react-bootstrap";
import "./CardComponent.css";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import Content from "./ContentFolder/Content";
function CardComponent(props) {
return (
<Router>
<div class="card">
<div className="uppercard">
<img
className="bookCover"
src={props.img}
alt=""
width="120px"
height="150px"
/>
<h3>{props.title}</h3>
<h6>By{props.author}</h6>
</div>
<div className="lowerCard">{props.points}</div>
<Link to={"/" + props.title + props.author}>Read</Link>
</div>
<Switch>
<Route
exact
path={`/${props.title+props.author}`}
component={Content}
>
<Content title={props.title} author={props.author}
points={props.points}
/>
</Route>
</Switch>
</Router>
);
}
export default CardComponent;
On clicking read I want to render this content component on a different page.
In summary, the goal is to display all the information on a new page when the user clicks on one of the card components.
import React from "react";
import Mynavbar from "../Partials/Mynavbar";
import MyFooter from "../Partials/Footer";
import { Container } from "react-bootstrap";
import "./Content.css";
function Content(props) {
return (
<div>
<Mynavbar />
<Container className="main">
<h4>{props.title}</h4>
<h6>By {props.author}</h6>
<ul>
{props.points.map((point, i) => {
return <li>{point}</li>;
})}
</ul>
</Container>
<MyFooter />
</div>
);
}
export default Content;
Problem: Router inside of CardComponent
The Router needs to exist at the highest level of the App. Everything that is inside of the Router and outside of the Switch will be rendered on every page. So right now your card code will show up even on the Content route. We want the Card and the Content to be separate Routes.
Problem: Ambiguous URL Structure
Do you need for your urls to look like "/${props.title+props.author}"? This is a very bad structure because you cannot possibly work backwards from the URL to the content. What is the content for "/Harry PotterJ.K. Rowling"? Which part is the title and which part is the author? There is no separator so you don't know. You would have to loop through a list of all books, joining their title and author and comparing it to your string.
A typical URL would be based on an id, like "/book/5". I don't see any mention of an id here so we can use the title.
Solution
An app routing might look like this:
function App() {
return (
<Router>
<Switch>
<Route path="/book/:title" component={BookDetails}/>
<Route path="/" component={BookList}/>
</Switch>
</Router>
)
}
Let's get rid of all the routing in CardComponent and make it just show a card for a book with a link to the book details.
function CardComponent(props: Book) {
return (
<div className="card">
<div className="uppercard">
<img
className="bookCover"
src={props.img}
alt=""
width="120px"
height="150px"
/>
<h3>{props.title}</h3>
<h6>By{props.author}</h6>
</div>
<div className="lowerCard">{props.points}</div>
<Link to={"/book/" + props.title}>Read</Link>
</div>
);
}
Our home page might show a list of these cards.
function BookList() {
// get books from somewhere -- a database? a json file?
const books = ???;
return (
<ul className="bookList">
{books.map((book) => (
<CardComponent {...book} key={book.title} />
))}
</ul>
);
}
BookDetails is a separate route, so we need to get the book from the URL.
function BookDetails(props: RouteComponentProps) {
// get the title from the URL
// is automatically encoded and needs to be decoded
const title = decodeURIComponent(props.match.params.title);
// find the book object from your data source
const book = ???
// from a JSON array: BOOKS.find(book => book.title.toLowerCase() === title.toLowerCase() );
// redirect to error page if no matching book
if ( ! book ) {
return <Redirect to="/404" />
}
// can render your Content component, but only after we get the book
return (
<Content {...book} />
)
}

How to direct to a new page when a button is clicked using ReactJS?

I am working in React.I have created a button ,which on click should lead the user to the newpage.I made a component About and imported it as well.
I created a function routeChange which would direct to a new page on Clicking the button.But when the button is clicked I am not being directed to any page .
Instead I get an error.
Probably there is not any error with folders.
I imported my About Component as:
import React from 'react';
import {Navbar,NavbarBrand, Jumbotron, Button} from 'reactstrap';
import './App.css';
import Description from './Description';
import './description.css';
import {useHistory,withRouter} from "react-router-dom";
import About from './About';
function App() {
const history=useHistory();
routeChange = () =>{
this.history.push('/About');
}
return (
<withRouter>
<Navbar color="dark">
<div className="container">
<NavbarBrand className="navbar-brand abs" href="/">
Cheat Sheet
</NavbarBrand>
</div>
</Navbar>
<Jumbotron>
<p className="lead">Quick Review ,Revision And Mnemonic Are Always Good</p>
<hr my-2/>
<p className="lead">Page is still under Construction</p>
<Button onClick={routeChange} className="About"color="primary">About Us</Button>
</Jumbotron>
<div className="img-thumbnail">
<Description/>
</div>
<div className="footer">
©Abhilekh Gautam all right reserved.
<p>Follow<a rel="noopener noreferrer"href="https://www.quora.com/profile/Abhilekh-Gautam-1" target="_blank">Abhilekh Gautam</a> On quora</p>
</div>
</withRouter>
)
}
export default App;
a couple issues here.
change function App (){} to const App = () => {} its going to help with your binding later because arrow functions are interpreted differently from declarative functions
this function needs some help
routeChange = () =>{
this.history.push('/About');
}
first of all you have to declare the function as a constant because App is a functional component not a class component.
second of all because App is a functional component you don't need the this keyword because routeChange is an arrow function and is bound to App
your final function should look like this:
const routeChange = () => {
history.push('/About');
}
make your button onClick handler an anonymous function so it is called on click only and not on render
<Button onClick={routeChange}/>
this code makes the route change function get called when the button renders. Instead change it to
<Button onClick={() => routeChange()}
make sure /About is a route to another component in your router or else you will get a 404 error or hit your no match component (if you have one)
your final product should look something like this
in app.js
import React from 'react';
import {Navbar,NavbarBrand, Jumbotron, Button} from 'reactstrap';
import './App.css';
import Description from './Description';
import './description.css';
import {useHistory,withRouter, BrowserRouter, Route, Switch} from "react-router-dom";
import About from './About';
function App() {
return (
<>
<Navbar color="dark">
<div className="container">
<NavbarBrand className="navbar-brand abs" href="/">
Cheat Sheet
</NavbarBrand>
</div>
</Navbar>
<BrowserRouter>
<Switch>
<Route exact path='/' component={Home}/>
<Route exact path='/About' component={About}
</Switch>
</BrowserRouter>
</>
)
}
then your home component would look like this:
import {useHistory} from 'react-router-dom'
const Home = () => {
const history = useHistory();
const routeChange = () => {
history.push('/About');
}
return (
<>
<Jumbotron>
<p className="lead">Quick Review ,Revision And Mnemonic Are Always Good</p>
<hr my-2/>
<p className="lead">Page is still under Construction</p>
<Button onClick={() => routeChange()} className="About"color="primary">About Us</Button>
</Jumbotron>
<div className="img-thumbnail">
<Description/>
</div>
<div className="footer">
©Abhilekh Gautam all right reserved.
<p>Follow<a rel="noopener noreferrer"href="https://www.quora.com/profile/Abhilekh-Gautam-1" target="_blank">Abhilekh Gautam</a> On quora</p>
</div>
</>
)
}
export default Home

How to pass state to components rendered by Router

I am making a React portfolio and one of the components will be an image gallery (needless to say I am a newbie to React, I wonder, or I'd not be asking this question). To do so, I will use a package (react-image-gallery), which allows me to customize several items. I already installed, and it works well, but I need to customize it - hide thumbnails and "play" and "fullscreen" buttons.
According to the documentation, it is possible to do so via the state. The issue is that I am failing to do so because the navigation of the App uses a router, and although I tried hard, I could not make the state pass into the component placed on Router. This is the code of the main component (the equivalent to App) which is not working:
import "./styles.css";
import {
HashRouter,
NavLink,
Route
} from "react-router-dom";
import React, { Component } from "react";
import Development from "./Development";
import Home from "./Home";
import Intro from "./Intro";
import Media from "./Media";
import StudyCase from './StudyCase';
import Stuff from "./Stuff";
class Main extends Component {
constructor() {
super();
this.state = {
showThumbnails: false
};
}
render() {
return (
<HashRouter>
<div>
<ul className='top-menu'>
<li>
<NavLink className='navs hvr-pulse' to='/'>
Home
</NavLink>
</li>
<li>
<NavLink className='navs hvr-pulse' to='/dev'>
Development
</NavLink>
</li>
<li>
<NavLink className='navs hvr-pulse' to='/media'>
Media
</NavLink>
</li>
<li>
<NavLink className='navs' to='/study-case'>
Study Case
</NavLink>
</li>
</ul>
<span className='bottom-slider'></span>
<div className='content'>
<Route exact path='/' component={Intro} />
<Route path='/dev' component={Development} />
<Route path='/media' component={Media} />
<Route path='/study-case' render={props => (<StudyCase {...this.state} showThumbnails={this.state.showThumbnails}/>)}/>
</div>
</div>
</HashRouter>
);
}
}
export default Main;
Can some of the colleagues point the error I am doing to me? Thanks in advance for the availability.
After some hours looking for the solution, I nailed it, and it was pretty basic, so a newbie could find the answer. It happened that the <StudyCase/> component had a component itself, and the state should live there. I was led to error by the rationale of a gallery package I was working with before, where state had to be manipulated in the same page of the router. Here is the code of the <StudyCase/> component, with the working state, if someone may need at some point:
import ImageGallery from 'react-image-gallery';
import React from 'react';
class StudyCase extends React.Component {
constructor() {
super();
this.state = {
showThumbnails: false,
showPlayButton: false,
showFullscreenButton: false,
showGalleryFullscreenButton: false,
};
}
render() {
return (
<ImageGallery
items={images}
showThumbnails={this.state.showThumbnails}
showPlayButton={this.state.showPlayButton && this.state.showGalleryPlayButton}
showFullscreenButton={
this.state.showFullscreenButton && this.state.showGalleryFullscreenButton
}
/>
// <ImageGallery
// items={images}
// showThumbnails={this.state.showThumbnails} />;
);
}
}
const images = [
{
original: 'https://picsum.photos/id/1018/1000/600/',
thumbnail: 'https://picsum.photos/id/1018/250/150/',
},
{
original: 'https://picsum.photos/id/1015/1000/600/',
thumbnail: 'https://picsum.photos/id/1015/250/150/',
},
{
original: 'https://picsum.photos/id/1019/1000/600/',
thumbnail: 'https://picsum.photos/id/1019/250/150/',
},
];
export default StudyCase;

Click on card then navigate to card page details in react

I created a page and show some card also some little details of cards
Now I want to click on any card navigate to this on show all details
How can I get to this page on react js ?
Is this need to Redux ?
I couldn't understand what you said completely, but you can use React-Router to navigate to different pages in Reactjs. To install it using npm, go to your Application directory and enter in command line npm install --save React-Router
Here is a simple code to navigate to different pages:
import React from "react";
import "./App.css";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
const Home=()=>
(<div>
<h2>Home</h2>
</div>
);
const About=()=>
(<div>
<h2>About</h2>
</div>
);
class App extends React.Component {
render() {
return (
<Router>
<div>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<Route exact path="/" component={Home}/>
<Route exact path="/about" component={About}/>
</div>
</Router>
);
}
}
export default App;
I hope it helped...
No need of Redux for your issue.
You just use React-router. you just create two component 1. Cards.js, 2. CardDetails.js and navigate to card details on click event of cards in Card.js
Cards.js
import React from "react";
import { withRouter } from "react-router";
class Cards extends React.Component {
goToCarddetails = (cardId) => {
localStorage.setItem("selectedCard", cardId);
this.props.history.push('/card-details');
// you can manage here to pass the clicked card id to the card details page if needed
}
render() {
return ( <div>
<div onClick = {()=>this.goToCarddetails('cardId1')}> card 1 </div>
<div onClick = {()=>this.goToCarddetails('cardId2')}> card 2 </div>
<div onClick = {()=>this.goToCarddetails('cardId3')}> card 3 </div>
</div>
)
}
}
export default withRouter(Cards);
With above on clicking any card you will be navigated to card details page.
CardDetails.js
import React from "react";
class CardDetails extends React.Component {
render() {
let selectedCardId = localStorage.getItem("selectedCard");
// you can get this cardId anywhere in the component as per your requirement
return ( <div>
card details here
</div>
)
}
}
export default CardDetails;
Note : I'm using react-router 4 here in example.

Resources