I am new to react 3 weeks so far. After login into my dummy app, I fetch users from the database (useEffect) as a button. I want to click on a specific user and access his/her data on the next page. Therefore, I use the context API and the useHistory to respectively send the data (state) of the selected user to the component and usehistory to navigate to that component. However, when route to that component, I receive UNDEFINED for the data I made accessible to the component.
import React, { useState, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import axios from 'axios';
import { useToken } from '../auth/useToken';
import { useUser } from '../auth/useUser';
import { ClassDetails } from './ClassPages/ClassDetails';
export const classSelectedContext = React.createContext();
export const ClassSelection = () => {
const user = useUser();
const [token, setToken] = useToken();
const [classesList, setClassesList] = useState([]);
const [selectedClass, setSelectedClass] = useState('');
const [className, setClassName] = useState('');
const [startDate, setStartDate] = useState('');
const [endDate, setEndDate] = useState('');
const history = useHistory();
const authStr = 'Bearer '.concat(token);
useEffect( () =>{
axios.get('http://localhost:8081/user/instructor-classes', {
headers: {
'Authorization': authStr
}
})
.then (res => {
setClassesList(res.data);
})
.catch(
err =>{
console.log(err);
history.push("/")
}
);
},[selectedClass]);
const AddNewClassClicked = () => {
axios.post('http://localhost:8081/user/class', {
className: className,
startDate: startDate,
endDate: endDate,
}, {
headers : {
'Authorization': authStr,
'Content-Type': 'application/json',
}
} )
.then(
//window.location.reload()
)
.catch(err => {
console.log(err)
});
}
const onSelectedClassClicked = () =>{
{history.push('class-detail')}
}
return (
<div className="content-container">
<div className="content-container">
<h1>Your current classes</h1>
{classesList.map(item => (
<button
value={item.classIdentifier}
onClick={(e) => {
setSelectedClass(e.target.value)
onSelectedClassClicked()
}}>
{item.className}
</button>
)) }
<classSelectedContext.Provider value={selectedClass} >
<ClassDetails />
</classSelectedContext.Provider>
</div>
<div className="content-container">
<h1>Add a new Class</h1>
<input
value={className}
onChange={e => setClassName(e.target.value)}
placeholder="Class Name" />
<input
value={startDate}
onChange={e => setStartDate(e.target.value)}
placeholder="Start Date of the Class" />
<input
value={endDate}
onChange={e => setEndDate(e.target.value)}
placeholder="End Date of the Class" />
<button
disabled={
!className || !startDate ||
!endDate
}
onClick={AddNewClassClicked}>add new Class</button>
</div>
</div>
)
}
So, After the click of the button, I am using history to get to ClassDetails (class-detail) where I can get the data passed to that component through the useEffect hook.
import React from 'react';
import { useState, useEffect, useContext } from 'react';
import { classSelectedContext } from '../ClassSelection';
import axios from 'axios';
import { useHistory } from 'react-router-dom';
import { useToken } from '../../auth/useToken';
export const ClassDetails = () => {
const [token, setToken] = useToken();
const history = useHistory();
const authStr = 'Bearer '.concat(token);
let context = useContext(classSelectedContext);
useEffect( () =>{
console.log(context)
axios.get(`http://localhost:8081/user/class/${context}`, {
headers: {
'Authorization': authStr
}
})
.then (res => {
console.log(res.data);
})
.catch(
err =>{
console.log(err);
console.log("An error happenned")
}
);
}, []);
return (
<div>
welcome {context}
<div>
{ GetClassDetail(context) }
</div>
{/* <classSelectedContext.Consumer>
{
variable => { GetClassDetail(variable)}
}
</classSelectedContext.Consumer> */}
</div>
)
}
At last, these are my routes
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { LogInPage } from './pages/LogInPage';
import { SignUpPage } from './pages/SignUpPage';
import { UserInfoPage } from './pages/UserInfoPage';
import { PrivateRoute } from './auth/PrivateRoute';
import { ClassSelection } from './pages/ClassSelection';
import { WelcomePage } from './pages/WelcomePage';
import { UserLogIn } from './pages/UserLogIn';
import { ClassDetails } from './pages/ClassPages/ClassDetails';
export const Routes = () => {
return (
<Router>
<Switch>
<PrivateRoute path="/class-detail" exact>
<ClassDetails />
</PrivateRoute>
<PrivateRoute path="/instructor-classes" exact>
<ClassSelection />
</PrivateRoute>
<PrivateRoute path="/select-school" exact>
<UserInfoPage />
</PrivateRoute>
<Route path="/user-login">
<UserLogIn />
</Route>
<Route path="/teacher-login">
<LogInPage />
</Route>
<Route path="/">
<WelcomePage />
</Route>
<Route path="/signup">
<SignUpPage />
</Route>
</Switch>
</Router>
);
}
Please check the code in this codesandbox link. I have tried to create a small application you are trying to make. I have added a wrapper of context to the router so that it will be available with route change. you can use render prop also and add provider with individual component like the below code.
<Route path="/" render={(props) => (<ContextB><Component2 {...props}/></ContextB>)}/>
Also history will work only if the component is wrapped inside "react router dom" in your code may be you are handling.