react, axios and route - reactjs

I'm testing some function, I discover a solution but I'm not sure that is correct way.
I need to load data from API so I used axios, and I need to share data between some child routes, I am currently using simple setState to keep values and passed them to the Route Components to be used.
Here is the MainContainer component
import React from 'react';
import axios from 'axios';
import { BrowserRouter, Route, Switch, Link, HashRouter, useLocation } from 'react-router-dom';
import Languages from './pages/Languages';
import Home from './pages/Home';
export default class MainContainer extends React.Component
{
constructor(props) {
super(props);
this.state = {
languages: null,
language:null,
}
}
get_init(language)
{
console.log("get_init")
var params = {
language:language,
}
axios
.get("https://xxxx.com/wp/it/api/init/")
.then(function(result) {
this.setState({languages:result.data.languages});
}.bind(this));
}
render() {
console.log("render")
return (
<div>
<Switch>
<Route path="/" component={() => <Languages get_init={this.get_init.bind(this)} languages={this.state.languages} />} exact />
<Route path="/:language/" component={(urlparam) => <Home language={urlparam.match.params.language} get_init={this.get_init.bind(this)} languages={this.state.languages} />} exact/>
<Route component={Error}/>
</Switch>
</div>
);
}
}
My Language Component is bellow
import axios from 'axios';
import React from 'react';
import LoaderData from './../helpers/LoaderData';
import { Link } from 'react-router-dom';
export default class Languages extends React.Component
{
constructor(props)
{
super(props);
if (props.languages==null)
{
this.props.get_init();
}
}
render() {
if (this.props.languages==null)
{
return '';
}
return (
<div>
<div className='main'>
LANGUAGE {Math.random()}<br/>
{
this.props.languages.map((language, i) =>
{
return (<div key={language.prefix}><Link to={language.prefix+"/"} >{language.name}</Link> <br/></div>)
})
}
</div>
</div>
);
}
}
is a correct way to build a website in react or there are better ways?

Related

React Router props.history

I'm a new to React.js with asp.net core, and I got an error that I don't understand.
I created protected route like that :
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import auth from './auth.js'
export const ProtectedRoute = ({ component: Component, ...rest }) => {
return (
<Route
{...rest}
render = {props => {
if(auth.estAuthentifier()){
return <Component {...props}/>
} else {
return <Redirect to={
{
pathname: "/",
state: {
from: props.location
}
}
} />
}
}}
/>
);
}
In my App.js, I added the protected route like that :
import React, { Component } from 'react';
import { BrowserRouter, Switch, Route } from 'react-router';
import { Login } from './components/Login'
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { ProtectedRoute } from './components/protected.route';
export default class App extends Component {
static displayName = App.name;
render () {
return (
<div>
<Switch>
<Route exact path="/" component={Login} />
<Layout>
<ProtectedRoute exact path="/home" component={Home}/>
</Layout>
<Route path="*" component={() => "404 NOT FOUND"}/>
</Switch>
</div>
);
}
}
And, the Layout component render all components with my NavBar included :
import React, { Component } from 'react';
import { Container } from 'reactstrap';
import { NavMenu } from './NavMenu';
import '../css/Layout.css';
export class Layout extends Component {
static displayName = Layout.name;
render () {
return (
<div className="conteneur-principal">
<NavMenu />
<Container>
{this.props.children}
</Container>
</div>
);
}
}
The problem is the next : I put the logout button in my navigation bar component but when I'm trying to logout and redirect to Login, i got the following error : TypeError: Cannot read property 'push' of undefined
NavMenu.js :
import React, { Component } from 'react';
import { NavLink } from 'reactstrap';
import { Link } from 'react-router-dom';
import auth from './auth';
import { withRouter } from 'react-router-dom';
import '../css/SideBarNav.css';
export class NavMenu extends Component {
static displayName = NavMenu.name;
constructor(props) {
super(props);
console.log(this.props);
this.deconnexion = this.deconnexion.bind(this);
}
deconnexion = () => {
auth.logout(() => {
this.props.history.push('/'); //LINE IN ERROR
})
}
render () {
return (
<div className="conteneur-menu">
<img src="images/familieu-logo-clear.png" alt="logo-familieu" title="logo-familieu" className="is-clickable logo-familieu"/>
<div className="conteneur-link">
<NavLink tag={Link} className="menu-link" to="/">Home</NavLink>
</div>
<input type="button" value="Déconnexion" className="btn-deconnexion" onClick={this.deconnexion}/>
</div>
);
}
}
What should I do to make my logout button work ?
Thanks alot
In NavMenu.js you are importing the withRouter, but is not used.
Wrap the export of component with withRouter like this:
export default withRouter(NavMenu);

Issues passing props via react-router-dom

I am attempting to pass data via react-router-dom, specifically I wanted to hold state data in the App.js file which I am using to route to different pages. I can't get the props to pass. What am I doing off here? Below is an example of what I am trying to do:
App.js
import React, { Component } from 'react';
import Home from './Home';
import {BrowserRouter as Router, Route,Switch, withRouter } from 'react-router-dom';
class App extends Component {
constructor(props) {
super(props);
this.state = {
testProps:7
}
}
render() {
return (
<Router>
<div>
<Route
exact path="/"
component = {Home}
render={(props) => <Home testProps={this.state.testProps} {...props} />}/>
</div>
</Router>
);
}
}
export default App;
Home.js
import React, { Component } from 'react';
class Home extends Component {
render() {
return (
<div>
{`passing props from state: ${this.props.testProps}`}
</div>
);
}
}
export default Home;
In my home page I see: passing props from state: undefined. Am I approaching this incorrectly?

How to change page title on separate header component depending on route with React?

I am using React and have my project structured in a way that I have layout components and then the main page components. I want to change the title of the page in the header component depending on which route the user came to.
Here is my App.jsx:
import React, { Suspense, lazy, Component } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Header from './layout/Header.jsx';
import Footer from './layout/Footer.jsx';
const Home = lazy(() => import('./pages/Home.jsx'));
const Weather = lazy(() => import('.pages/Weather.jsx'));
const Encryption = lazy(() => import('./pages/Encryption.jsx'));
const Video = lazy(() => import('./pages/Video.jsx'));
class App extends Component {
render() {
return (
<Router>
<>
<Header/>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/weather" component={Weather}/>
<Route path="/encryption" component={Encryption}/>
<Route path="/video" component={Video}/>
</Switch>
</Suspense>
<Footer/>
</>
</Router>
);
}
}
export default App;
My Header.jsx component is like so:
import React, { Component } from 'react';
class Header extends Component {
constructor(props) {
super(props);
}
render() {
return (
<h1>Page Title</h1>
);
}
}
export default Header;
import React, { Component } from "react";
import { withRouter } from "react-router-dom";
class Header extends Component {
constructor(props) {
super(props);
}
render() {
const path = this.props.location.pathname.slice(1);
return (
<div>
<h1>{path}</h1>
</div>
);
}
}
export default withRouter(Header);
Working example here: https://codesandbox.io/s/zl3y72k0pp
thre HOC withRouter will provide the props match, location and history to your component.
then your can use location.pathname to manage the rendering of your component

Can't access my match.props in react router

I'm gonna post some code, because it appears I have not included something.
import React from 'react';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import {updateSearch, getSearchResults} from '../actions/qb-actions';
import {valueAccepted} from '../actions/tree-actions';
import {addNewElement} from '../services/commonComponents';
import QueryBuilder from './QueryBuilder';
import SearchResults from './SearchResults';
import FontAwesome from 'react-fontawesome';
import {checkIncludeColumns} from '../services/commonComponents';
import {removeSpaces} from '../services/values';
import { Button } from 'reactstrap';
class SearchBooksAdvanced extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
componentDidMount(){
const { match: { params } } = this.props;
//I want to use match.params here, but it is coming back undefined.
}
qb=()=>{
}
postResults = () => {
this.qb();
}
render() {
return (<div >
<QueryBuilder postResults={this.postResults}/>
<SearchResults
qb={qb => {this.qb = qb}}
tree={this.props.tree.tree}
/>
</div>);
}
}
function mapStateToProps(state){
return{
options: state.options,
tree: state.tree,
goToSearch: state.goToSearch
};
}
export default connect(mapStateToProps, {updateSearch, getSearchResults})(SearchBooksAdvanced);
A little abbreviated class. Here is where I am calling my routings:
<main>
<Switch>
<AuthenticatedRoute login={this.props.login} path={`${this.props.match.path}`} exact component={Landing} isLoggedOut={this.props.login.ckUser.isLoggedOut}/>
<AuthenticatedRoute login={this.props.login} path={`${this.props.match.path}/search/:searchID`} exact component={SearchBooksAdvanced} isLoggedOut={this.props.login.ckUser.isLoggedOut}/>
<AuthenticatedRoute login={this.props.login} path={`${this.props.match.path}/book/:bookID`} exact component={BookDetail} isLoggedOut={this.props.login.ckUser.isLoggedOut}/>
<AuthenticatedRoute login={this.props.login} path={`${this.props.match.path}/routing/:routingID/:versionID`} exact component={RoutingDetail} isLoggedOut={this.props.login.ckUser.isLoggedOut}/>
<Redirect to={`${this.props.match.url}`} />
</Switch>
</main>
My AuthenicatedRoute class is as follows:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
const AuthenticatedRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props =>
(
!props.isLoggedOut && localStorage.getItem('user') ?
<Component {...props}/>
:
<span><Redirect to={{
pathname: '/bis/login',
state: { from: props.location }
}}/><span>redirected</span></span>
)}/>
);
export default AuthenticatedRoute
What is weird here, is my props.match.params.someID worked for my other two classes, but when I called it for SeachBooksAdvanced class it fails to find it. Please let me know if you see an inconsistency in my code. TIA.
You want to use the withRouter HOC on route components that you use connect on.
import { withRouter } from "react-router-dom";
// ...
export default withRouter(
connect(
mapStateToProps,
{ updateSearch, getSearchResults }
)(SearchBooksAdvanced)
);

React Component Does Not Mount

I am in need of some help. I'm working on a create-react-app using React-Router. The issue that I'm seeing is that when I run my app, I should be able to see individual student information when I click on their name. Instead, nothing renders.
Here is the code for the component (students.js) that is not rendering:
import React, { Component } from 'react';
import axios from 'axios';
export default class Student extends Component {
constructor() {
super();
this.state = {
studentInfo: {}
}
}
componentDidMount(){
console.log('fired')
axios.get(`http://localhost:3005/students/${this.props.match.params.id}`)
.then(res => {
this.setState({studentInfo: res.data})
})
.catch(err => console.log(err))
}
render() {
return (
<div className="box">
<h1>Student:</h1>
<h1>{this.state.studentInfo.first_name}
{this.state.studentInfo.last_name}</h1>
<h3>Grade: {this.state.studentInfo.grade}</h3>
<h3>Email: {this.state.studentInfo.email}</h3>
</div>
)
}
}
I have tried a console.log in the componentDidMount method of my students.js file to see if it is mounting properly and I found that it would not fire. When I tried to check state with the React Dev Tools, I saw that there was no state.
I have a similar component called classList.js that has a similar setup that is working properly.
classList.js:
import React, { Component } from 'react';
import axios from 'axios';
import {Link} from 'react-router-dom';
export default class ClassList extends Component {
constructor() {
super();
this.state = {
students: []
}
}
componentDidMount(){
axios.get(`http://localhost:3005/students?
class=${this.props.match.params.class}`)
.then(res => {
this.setState({students: res.data});
})
.catch(err => console.log(err))}
render() {
const students = this.state.students.map((student,i) =>
<Link key={i} to={`/student/${student.id}`}><h3>{student.first_name}
{student.last_name}</h3></Link>
)
return (
<div className="box">
<h1>{this.props.match.params.class}</h1>
<h2>ClassList:</h2>
{students}
</div>
)
}
}
I've checked my routes and my link tags and they seem fine.
Routes.js:
import React from 'react';
import {Switch, Route} from 'react-router-dom';
import Home from './components/Home/Home';
import About from './components/About/About';
import ClassList from './components/ClassList/ClassList';
import Student from './components/Student/Student'
export default (
<Switch>
<Route exact path='/' component={Home} />
<Route path='/about' component={About} />
<Route path='/classlist/:class' component={ClassList} />
<Route path='student/:id' component={Student} />
</Switch>
)
Any thoughts? Thanks!
I'm pretty sure it doesn't find the student route because you're missing an /
<Route path='student/:id' component={Student} />
should be
<Route path='/student/:id' component={Student} />

Resources