I am trying to pass a pass down id from getUsers() to a child component as a prop.
App.jsx
import React, { Component } from 'react';
import { Route, Switch } from 'react-router-dom';
import axios from 'axios';
import About from './components/About';
import NavBar from './components/NavBar';
import Form from './components/forms/Form';
import Logout from './components/Logout';
import UserStatus from './components/UserStatus';
import Seeds from './components/Seeds';
import Message from './components/Message';
class App extends Component {
constructor() {
super();
this.state = {
users: [],
title: 'Project',
isAuthenticated: false,
messageName: null,
messageType: null,
restaurant: '',
email: '',
id: '',
username: '',
active: '',
admin: '',
};
this.logoutUser = this.logoutUser.bind(this);
this.loginUser = this.loginUser.bind(this);
this.createMessage = this.createMessage.bind(this);
this.removeMessage = this.removeMessage.bind(this);
this.userStatus = this.userStatus.bind(this);
};
componentWillMount() {
if (window.localStorage.getItem('authToken')) {
this.setState({ isAuthenticated: true });
};
};
componentDidMount() {
this.getUsers();
this.userStatus();
};
getUsers() {
axios.get(`${process.env.REACT_APP_WEB_SERVICE_URL}/users`)
.then((res) => { this.setState({ users: res.data.data.users }); })
.catch((err) => { });
};
logoutUser() {
window.localStorage.clear();
this.setState({ isAuthenticated: false });
};
loginUser(token) {
window.localStorage.setItem('authToken', token);
this.setState({ isAuthenticated: true });
this.getUsers();
this.createMessage('Welcome', 'success');
};
userStatus(event) {
const options = {
url: `${process.env.REACT_APP_WEB_SERVICE_URL}/auth/status`,
method: 'get',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${window.localStorage.authToken}`
}
};
return axios(options)
.then((res) => {
console.log(res.data)
console.log(res.data.data)
this.setState({
restaurant: res.data.data.restaurant,
email: res.data.data.email,
id: res.data.data.id,
username: res.data.data.username,
active: String(res.data.data.active),
admin: String(res.data.data.admin),
})
})
.catch((error) => { console.log(error); });
};
createMessage(name='Sanity Check', type='success') {
this.setState({
messageName: name,
messageType: type
});
setTimeout(() => {
this.removeMessage();
}, 3000);
};
removeMessage() {
this.setState({
messageName: null,
messageType: null
});
};
render() {
return (
<div>
<NavBar
title={this.state.title}
isAuthenticated={this.state.isAuthenticated}
/>
<section className="section">
<div className="container">
{this.state.messageName && this.state.messageType &&
<Message
messageName={this.state.messageName}
messageType={this.state.messageType}
removeMessage={this.removeMessage}
/>
}
<div className="columns">
<div className="column is-half">
<br/>
<Switch>
<Route exact path='/' render={() => (
<SpotifyAuth
/>
)} />
<Route exact path='/about' component={About}/>
<Route exact path='/register' render={() => (
<Form
formType={'Register'}
isAuthenticated={this.state.isAuthenticated}
loginUser={this.loginUser}
createMessage={this.createMessage}
/>
)} />
<Route exact path='/login' render={() => (
<Form
formType={'Login'}
isAuthenticated={this.state.isAuthenticated}
loginUser={this.loginUser}
createMessage={this.createMessage}
/>
)} />
<Route exact path='/logout' render={() => (
<Logout
logoutUser={this.logoutUser}
isAuthenticated={this.state.isAuthenticated}
/>
)} />
<Route exact path='/status' render={() => (
<UserStatus
isAuthenticated={this.state.isAuthenticated}
/>
)} />
<Route exact path='/seeds' render={() => (
<Seeds
isAuthenticated={this.state.isAuthenticated}
userStatus={this.userStatus}
/>
)} />
</Switch>
</div>
</div>
</div>
</section>
</div>
)
}
};
export default App;
Seeds.jsx
import React, { Component } from 'react';
import axios from 'axios';
class Seeds extends Component{
constructor (props) {
super(props);
this.state = {
restaurant:'',
email: '',
id: '',
username: '',
active: '',
admin: '',
template:'',
formSeeds:{
type1:'',
type2:'',
type3:'',
},
formEditMenu:{
item:'',
item2:'',
item3:'',
}
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmitSeeds = this.handleSubmitSeeds.bind(this);
this.handleSubmitItems = this.handleSubmitItems.bind(this);
};
componentDidMount() {
if (this.props.isAuthenticated) {
this.getSeeds();
}
};
getSeeds(event) {
const {userStatus} = this.props
const options = {
url: `${process.env.REACT_APP_WEB_SERVICE_URL}/seeds/${userStatus.id}`,
method: 'get',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${window.localStorage.authToken}`
}
};
return axios(options)
.then((res) => {
console.log(res.data.data)
this.setState({
restaurant: res.data.data[0].restaurant,
id: res.data.data[0].id,
template: res.data.data[0].content
})
console.log(userStatus.id);
})
.catch((error) => { console.log(error); });
};
handleChange(event){
const objformSeeds = this.state.formSeeds;
objformSeeds[event.target.name] = event.target.value;
this.setState(objformSeeds);
const formEditMenu = this.state.formEditMenu;
formEditMenu[event.target.name] = event.target.value;
this.setState(formEditMenu);
}
handleSubmitSeeds(event) {
event.preventDefault();
const {userStatus} = this.props
const data = {
type1: this.state.formSeeds.type1,
type2: this.state.formSeeds.type2,
type3: this.state.formSeeds.type3,
};
const url = `${process.env.REACT_APP_WEB_SERVICE_URL}/handle_seeds/${userStatus.id}`;
axios.post(url, data)
.then((res) => {
console.log(data);
})
.catch((err) => {
});
};
handleSubmitCoffees(event) {
event.preventDefault();
const {userStatus} = this.props
const data = {
item: this.state.formEditMenu.item,
item2: this.state.formEditMenu.items2,
items3: this.state.formEditMenu.items3,
};
const url = `${process.env.REACT_APP_WEB_SERVICE_URL}/edit_menu/${userStatus.id}`;
axios.post(url, data)
.then((res) => {
console.log(data);
})
.catch((err) => {
});
};
render(){
var __html = this.state.template;
var template = { __html: __html };
return (
<div id="parent">
<div dangerouslySetInnerHTML={template}/>
<form>
<input type='text' name='name' onChange={this.handleChange}/><br/>
<button type="button" onClick={this.handleSubmitItems} />
</form>
</div>
);
}
}
export default Seeds;
but I'm getting userStatus undefined.
XHR failed loading: GET "http://localhost/seeds/undefined".
console.log(userStatus):
userStatus(event) {
const options = {
url: "".concat("http://localhost", "/auth/status"),
method: 'get',
headers: {
'Content-Type': 'application/json',
Authoriza…
what am I missing?
I would recommend you pass down the id only because you using this.userStatus is the function
userStatus={this.userStatus}
You need to change to
userStatus={this.state.id}
Related
I am trying to implement protected routes for orders router but even the user is authenticated it always redirect to login. I have used Navigate component from react-router-dom and I have passed the isAuth state for app.js to privateRoute.js component and I received that isAuth as prop in privateRoute.js but if I don't use the navigate component then I get the isAuth true when user authenticates but it I used navigate component then it redirects to login routes before isAuth is set to true. Need help!!
//app.js
function App(props) {
const navigate = useNavigate();
const [authState, setAuthState] = useState({
isAuth: false,
token: null,
userId: null,
});
const [showNav, setShowNav] = useState(true);
useEffect(() => {
if (window.location.href.includes("admin")) {
setShowNav(false);
}
const token = localStorage.getItem("token");
const expiryDate = localStorage.getItem("expiryDate");
if (!token || !expiryDate) {
return;
}
const userId = localStorage.getItem("userId");
const remainingMilliseconds =
new Date(expiryDate).getTime() - new Date().getTime();
setAuthState((prevState) => {
return {
...prevState,
isAuth: true,
token: token,
userId: userId,
};
});
setAutoLogout(remainingMilliseconds);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [authState.isAuth]);
const handleUserCredentialsSubmission = (userData, setErrors) => {
const formData = new FormData();
formData.append("name", userData.name);
formData.append("email", userData.email);
formData.append("password", userData.password);
fetch("http://localhost:3080/signup", { method: "POST", body: formData })
.then((res) => {
if (res.status !== 200 && res.status !== 201) {
if (res.status === 409) {
throw new Error("Email address already exists!");
} else {
throw new Error("Creating a user failed!");
}
}
return res.json();
})
.then((resData) => {
navigate("/login");
})
.catch((err) => {
setErrors((prevState) => {
return {
...prevState,
signupError: err.message,
};
});
throw new Error(err);
});
};
const logoutHandler = () => {
setAuthState((prevState) => {
return {
...prevState,
isAuth: false,
token: null,
};
});
localStorage.removeItem("token");
localStorage.removeItem("userId");
localStorage.removeItem("expiryDate");
navigate("/login");
};
const setAutoLogout = (remainingTime) => {
setTimeout(() => {
logoutHandler();
}, remainingTime);
};
const handleUserlogin = (userData, setErrors, setUserCredentials) => {
const formData = new FormData();
formData.append("email", userData.email);
formData.append("password", userData.password);
fetch("http://localhost:3080/login", { method: "POST", body: formData })
.then((res) => {
if (res.status !== 200 && res.status !== 201) {
throw new Error("Invalid Email Address & Password");
}
return res.json();
})
.then((resData) => {
setAuthState((prevState) => {
return {
...prevState,
isAuth: true,
token: resData.token,
userId: resData.userId,
};
});
localStorage.setItem("token", resData.token);
localStorage.setItem("userId", resData.userId);
const remainingMilliseconds = 60 * 60 * 1000;
const expiryDate = new Date(
new Date().getTime() + remainingMilliseconds
);
localStorage.setItem("expiryDate", expiryDate.toISOString());
navigate("/");
})
.catch((err) => {
setAuthState((prevState) => {
return {
...prevState,
isAuth: false,
token: null,
userId: null,
};
});
setUserCredentials((prevState) => {
return {
...prevState,
email: "",
password: "",
};
});
setErrors((prevState) => {
return {
...prevState,
loginError: err.message,
};
});
throw new Error(err);
});
};
const handleAddToCart = (productId) => {
fetch("http://localhost:3080/cart", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + authState.token,
},
body: JSON.stringify({
prodId: productId,
}),
})
.then((res) => {
if (res.status !== 200 && res.status !== 201) {
throw new Error("User does not Exists");
}
return res.json();
})
.then((resData) => {
navigate("/cart");
})
.catch((err) => {
throw new Error(err);
});
};
console.log(authState.isAuth);
return (
<div className="App">
{showNav && (
<Nav
token={authState.token}
isAuth={authState.isAuth}
onLogout={logoutHandler}
/>
)}
{/* <Nav /> */}
<Routes>
<Route
path="/product"
element={
<Product isAuth={authState.isAuth} AddToCart={handleAddToCart} />
}
/>
<Route
path="/product/:productId"
element={
<ProductDetails
{...props}
isAuth={authState.isAuth}
AddToCart={handleAddToCart}
/>
}
/>
<Route path="/cart" element={<Cart token={authState.token} />} />
<Route
path="/orders"
element={
<PrivateRoute {...authState}>
<Orders token={authState.token} />
</PrivateRoute>
}
/>
<Route
path="/checkout"
element={<Checkout token={authState.token} />}
/>
<Route path="/login" element={<Login onSingIn={handleUserlogin} />} />
<Route
path="/signup"
element={<Signup onSignUp={handleUserCredentialsSubmission} />}
/>
<Route path="/admin/*" element={<Admin />}>
<Route
path="product"
element={<AddProduct token={authState.token} />}
/>
<Route path="products" element={<AdminProducts Admin={!showNav} />} />
</Route>
<Route path="/" element={<Home />} />
{/* <Route path="*" element={<Navigate to="/" />} /> */}
</Routes>
</div>
);
}
export default App;
//privateRoute.js
const PrivateRoute = (props) => {
console.log(props.isAuth);
if (!props.isAuth) {
return <Navigate to="/login" replace />;
}
return props.children;
};
export default PrivateRoute;
The authState.isAuth state's initial value looks to match the "unauthenticated" state, so when the app is initially loading/mounting and the user is on a protected route the PrivateRoute bounces them off it to the login route to authenticate.
Use an initial authState.isAuth value that isn't one of the confirmed/validated/verified authentication state values. In other words, anything other than true or false. Update the PrivateRoute component to check for this initial condition and conditionally render null or some loading indicator until the authentication status is confirm.
App
const [authState, setAuthState] = useState({
isAuth: undefined,
token: null,
userId: null,
});
privateRoute.js
const PrivateRoute = ({ isAuth }) => {
if (isAuth === undefined) {
return null; // or loading indicator/spinner/etc
}
return isAuth
? children
: <Navigate to="/login" replace />;
};
Note that you will need to explicitly set the authState.isAuth state for the unauthenticated logic paths, i.e. authentication fails, token expired, etc.
Given is an application with which you can manage users.
Click on a button to be redirected to the UserManagement page:
<Router>
<Button><Link to="/user" id="OpenUserManagementButton">
<i className="fa fg"></i>UserManagement</Link></Button>
<Routes>
<Route path="/user" element={<UserManagementPage />} />
</Routes>
</Router>
At the same time the click should load all available users from the backend.
For this, the following function is now available in the ManagementAction.js.
export function showallUser() {
console.log("Show all Users")
return dispatch => {
dispatch(getShowUserManagementAction());
showUser().then(userSession => {
const action = getShowUserManagementActionSuccess(userSession);
dispatch(action);
}, error => { dispatch(getShowUserManagementErrorAction(error)); }).catch(error => { dispatch(getShowUserManagementErrorAction(error)); })
}
}
function showUser() {
const token = localStorage.getItem("token")
const requestOptions = {
method: 'GET',
headers: { 'Authorization': `Bearer ${token}` },
};
return fetch('https://localhost:443/user/', requestOptions)
.then(handleResponse)
.then(userSession => {
return userSession;
});
}
The UserManagementPage looks like this:
class UserManagementPage extends Component {
constructor(props) {
super(props);
this.state = { userList: [] }
}
render() {
return (
<div className="page-content" id="UserManagementPage" style={{ background: 'white' }}>
<UserList />
{this.state.users}
</div>
)
}
}
export default UserManagementPage
question: How can I use the showUser and showallUser functions to show me all users ?
I have been doing js for about a month now, and I am writing this program where I am using clarifai API to see which celebrity a person on the photo resembles the most.
I want to pass the output as props to Rank component to render it, but
I get the
Type error: clarifaiResults.map is not a function at App.transformResponse
Basically, the response I want to pass as props is the
const clarifaiResults = response.outputs[0].data.regions[0].data.concepts[0].name;
part that I get in console.log now
I am assuming it's because there is no output yet when the app tries to render the component, but I can't figure out what's wrong with the code. Thank you!
App.js
import React, { Component } from 'react';
import './App.css';
import SignIn from './Component/SignIn/SignIn.js';
import Register from './Component/Register/Register.js';
import Particles from 'react-particles-js';
import Logo from './Component/Logo/Logo.js';
import Navigation from './Component/Navi/Navigation.js';
import ImageLinkForm from './Component/Form/ImageLinkForm.js';
import Rank from './Component/Rank/Rank.js'
import Clarifai from 'clarifai';
import FaceRecognition from './Component/Face/FaceRecognition.js';
import FaceComparison from './Component/Comparison/FaceComparison.js';
const app = new Clarifai.App({
apiKey: 'MYSUPERSECRETKEY'
});
const initialState = {
input: "",
imageUrl: "",
results: [],
route: "SignIn",
user: {
id: "",
name: "",
email: "",
entries: 0,
joined: "",
},
};
const particleOptions = {
particles: {
number: {
value: 40,
density: {
enable: true,
value_area: 800,
},
}
}
}
class App extends Component{
constructor() {
super();
this.state = initialState;
}
transformResponse = (response) => {
const clarifaiResults = response.outputs[0].data.regions[0].data.concepts[0].name;
const results = clarifaiResults.map((ingredient) => ({
ingredients: ingredient.name,
probablitiy: ingredient.value,
}));
this.setState({results: results.celebrityName});
return {results: []};
};
onInputChange = (event) => {
this.setState({input: event.target.value});
}
onSubmit = () => {
this.setState({imageUrl: this.state.input});
app.models
.predict(
Clarifai.CELEBRITY_MODEL,
this.state.input)
.then(response => {
console.log(response.outputs[0].data.regions[0].data.concepts[0].name)
if (response) {
fetch ('http://loclhost:3000', {
method: 'post',
headers: {'Conent-Type' : 'application/json'},
body: JSON.stringify({
input: this.state.user.input
})
})
.then((response) => response.json())
.then(count => {
this.setState(Object.assign(this.state.user, {entries:count}))
})
}
this.transformResponse(response);
})
.catch(err => console.log(err));
};
;
onRouteChange = (route) => {
if (route === 'signout'){
this.setState({isSignedIn: false})
} else if (route ==='home'){
this.setState({isSignedIn: true})
}
this.setState({route: route});
}
render() {
let { isSignedIn, imageUrl, route, results} = this.state;
return (
<div className="App">
<Particles className='particles'
params={particleOptions}
/>
<Navigation isSignedIn={isSignedIn} onRouteChange={this.onRouteChange}/>
{ route ==='home'
? <div>
<Logo />
<Rank
results = {results}/>
<ImageLinkForm
onInputChange={this.onInputChange}
onSubmit={this.onSubmit}
/>
<FaceRecognition
imageUrl={imageUrl}
/>
<FaceComparison
results = {results}
/>
</div>
: (
route === 'SignIn'
? <SignIn onRouteChange={this.onRouteChange}/>
: <Register />
)
}
</div>
);
};
}
export default App;
Rank.js
import React from 'react';
const Rank = ({results}) => {
const prediction = results.map((result) => {
const {ingredients} = result;
return (
<div>
<li className="celebrityName">{ingredients}</li>
</div>
);
});
if (prediction && prediction.length>1) {
return (
<div>
<div className='white f3'>
You look a lot like...
</div>
<div className='white f1'>
{results}
</div>
</div>
);
} else {
return (
<div>
</div>
)
}
};
export default Rank;
I have an App.jsx parent component and a TopBar.js child. What I would like to do is get the appId parameter from the url and pass it into my TopBar child component. The problem is that I don't know how to use match.params.appId like CategoryPage (<CategoryPage categoryId = {match.params.categoryId} />) because I get an error message: match is not defined, which seems normal since my child component is not included in a <Route> component. I looked at the documentation and I can only find the classic case, is there another way to retrieve a route parameter and for example store it in a state in order to reuse it?
Thank you in advance for any help or advice, I am new to this project and I am gradually integrating the particularities of the code.
App.jsx
export default class App extends PureComponent {
static childContextTypes = {
apiKEY: PropTypes.string,
apiURL: PropTypes.string,
appName: PropTypes.string,
loginToken: PropTypes.string,
userId: PropTypes.string,
};
constructor(props) {
super(props);
const parsed = queryString.parse(window.location.search);
const state = {
apiKey: null,
appName: null,
fetchApiKeyError: null,
fetchApiKeyPending: false,
fetchApiKeyDone: false,
};
['auth_token', 'userId'].forEach((key) => {
state[key] = parsed[key] || localStorage.getItem(key);
if (parsed[key]) localStorage.setItem(key, parsed[key]);
});
this.state = state;
this.handleErrorAuth = this.handleErrorAuth.bind(this);
}
getChildContext() {
const {
auth_token: loginToken, userId, apiKey, appName,
} = this.state;
return {
apiURL: process.env.REACT_APP_API_URL,
loginToken,
userId,
apiKEY: apiKey,
appName,
};
}
renderRedirect = () => {
const isLogged = localStorage.auth_token && localStorage.userId;
// This is a private app, so we need to be logged all time
if (!isLogged) {
window.location = `${process.env.REACT_APP_AUTH_URL}?redirect_uri=${window.location}`;
return null;
}
return null;
}
fetchApiKey = (appId, authToken) => {
if (!authToken) return;
this.setState({ fetchApiKeyPending: true });
const storageKey = `apiKey_${appId}`;
const nameStorageKey = `name_${appId}`;
const apiKey = localStorage.getItem(storageKey);
const appName = localStorage.getItem(nameStorageKey);
// ApiKey and appName already in localStorage
if (apiKey && appName) {
this.setState({
fetchApiKeyPending: false,
fetchApiKeyDone: true,
apiKey,
appName,
});
return;
}
// flush all previous keys
Object.keys(localStorage)
.filter((val) => val.indexOf('apiKey_') + 1 || val.indexOf('name_') + 1)
.forEach((val) => localStorage.removeItem(val));
// get ApiKey
fetch(`${process.env.REACT_APP_API_URL}/apps/${appId}/infos`, {
headers: {
Authorization: `Bearer ${authToken}`,
},
}).then((data) => {
if (!data.ok) throw new Error(data.status);
return data;
})
.then((data) => data.json())
.then(({ key, name }) => {
localStorage.setItem(storageKey, key);
localStorage.setItem(nameStorageKey, name);
this.setState({
fetchApiKeyPending: false,
fetchApiKeyDone: true,
fetchApiKeyError: null,
apiKey: key,
appName: name,
});
})
.catch((e) => this.setState({
fetchApiKeyPending: false,
fetchApiKeyDone: true,
fetchApiKeyError: e,
apiKey: null,
appName: null,
}));
};
getLastAppId = () => {
const storageKey = Object.keys(localStorage).filter(
(val) => val.indexOf('apiKey_') + 1,
)[0];
return storageKey ? storageKey.split('apiKey_')[1] : null;
};
switch = (location) => {
const {
fetchApiKeyPending,
fetchApiKeyDone,
apiKey,
auth_token: loginToken,
fetchApiKeyError,
} = this.state;
return (
<Switch location={location}>
{apiKey && [
<Route
key="1"
path="/:appId/categories/:categoryId/new_article"
render={({ match }) => (
<DefaultLayout>
<NewArticlePage categoryId={match.params.categoryId} />
</DefaultLayout>
)}
/>,
<Route
key="2"
path="/:appId/articles/:articleId"
render={({ match }) => (
<DefaultLayout>
<ModifyArticlePage articleId={match.params.articleId} />
</DefaultLayout>
)}
/>,
<Route
key="3"
path="/:appId/createCategory"
render={({ match }) => (
<CenteredLayout
backButtonProps={{
to: `/${match.params.appId}/categories`,
}}
>
<NewCategoryPage />
</CenteredLayout>
)}
apikey
/>,
<Route
key="4"
path="/:appId/categories/:categoryId/modify"
render={({ match }) => (
<CenteredLayout>
<NewCategoryPage categoryId={match.params.categoryId} />
</CenteredLayout>
)}
/>,
<Route
key="5"
path="/:appId/categories/:categoryId"
render={({ match }) => (
<CenteredLayout
backButtonProps={{
to: `/${match.params.appId}/categories`,
}}
>
<CategoryPage categoryId={match.params.categoryId} />
</CenteredLayout>
)}
/>,
<Route key="6" path="/:appId/categories" component={CategoriesPage} />,
]}
<Route path="/welcome" component={WelcomePage} />
<Route path="/app_not_found" render={() => <AppNotFoundPage titleKey="press" />} />
<Route
path="/:appId/"
exact={false}
render={({ match }) => {
if (fetchApiKeyError) {
return <Redirect to="/app_not_found" />;
}
if (!fetchApiKeyDone || fetchApiKeyPending) {
return (
[
<OnMountExecuter
key="1"
execute={this.fetchApiKey}
params={[match.params.appId, loginToken]}
/>,
<Loading key="2" style={{ fontSize: 36 }} />,
]
);
}
return <Redirect to={`/${match.params.appId}/categories`} />;
}}
/>
<Route
path="/"
render={() => {
if (localStorage.auth_token && localStorage.userId) {
const appId = this.getLastAppId();
if (appId) {
return <Redirect to={`/${appId}/categories`} />;
}
}
return <Redirect to="/welcome" />;
}}
/>
</Switch>
);
};
handleErrorAuth() {
this.setState({
auth_token: null,
userId: null,
});
localStorage.clear();
}
renderContent(location) {
return (
<HttpsRedirect>
<IntlProvider locale={language} messages={messages[language]}>
<div id="container">
<div id="content-container">
<AuthorizeChecker onError={this.handleErrorAuth} />
<UserContextProvider>
<UserContext.Consumer>
{(user) => <TopBar user={user} />}
</UserContext.Consumer>
{this.switch(location)}
</UserContextProvider>
</div>
</div>
</IntlProvider>
</HttpsRedirect>
);
}
render() {
return (
<BrowserRouter>
<Route
render={({ location }) => this.renderRedirect(location) || this.renderContent(location)}
/>
</BrowserRouter>
);
}
}
You could access the match object from any grand child component of a Router component using the context created by the react router, it is found under, context =>router=>match. From there you can do whatever you want with it.
You can access the context under this.context in any class based component, in a hooks component you have to use the hook useContext
Also note that newer versions of react router have hooks that might help you, like
useRouteMatch and useParams.
The below code renders a list of planets (from this API: https://swapi.dev/).I'm trying to find a way to make my planets clickable. When a specific planet is clicked in the list, it should open up a detail page with specific info (pulled from API) on the planet that has been clicked. Can I do this with or ? What is the best practice way to do this?
import React, { PureComponent } from 'react'
import axios from "axios";
class Home extends PureComponent {
constructor(props) {
super(props)
this.state = {
planets: [],
filteredPlanets: []
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(e){ // eslint-disable-next-line
let planetssearchlist = this.state.planets.filter(planet => {
if(planet.name){
if(planet.name.toLowerCase().includes(e.target.value.toLowerCase())){
return true
}
}
})
this.setState({
filteredPlanets: planetssearchlist
})
}
componentDidMount(){
axios({
method: "GET",
url: "https://swapi.dev/api/planets/"
})
.then(response => {
console.log(response)
let planetslist = response.data.results;
this.setState({planets: planetslist, filteredPlanets: planetslist})
})
.catch(error => {
console.log("You've made an error with the planets load charles: ",error)
})
}
render() {
return (
<div>
<h1>Star Wars Planets</h1>
<form>
<input placeholder="searchbar" type="text" onChange={this.handleChange}></input>
</form>
{
this.state.filteredPlanets.map((planet,i) => (
<p key={i}>{planet.name}</p>
))
}
</div>
)
}
}
export default Home
Add a new function to get the planet info. In your map add onClick event handler to get the planet info for the clicked planet.
Add two new variable to your state
this.state = {
planets: [],
filteredPlanets: [],
planetInfo: {},
isGettingPlanetInfo: false,
};
Add a function to get the planet info
getPlanetInfo = url => {
this.setState({
isGettingPlanetInfo: true
})
axios({
method: "GET",
url: url
})
.then(response => {
console.log(response.data)
this.setState({
planetInfo: response.data,
isGettingPlanetInfo: false,
})
})
.catch(error => {
this.setState({
isGettingPlanetInfo: false
})
console.log(
"You've made an error with the planets load charles: ",
error
);
});
};
Add on click event handler to the planet
{this.state.filteredPlanets.map((planet, i) => (
<p onClick={() => this.getPlanetInfo(planet.url)} key={i}>
{planet.name}
</p>
))}
Home component
import React, { PureComponent } from 'react';
import axios from 'axios';
export default class Home extends PureComponent {
constructor(props) {
super(props);
this.state = {
planets: [],
filteredPlanets: [],
planetInfo: {},
isGettingPlanetInfo: false,
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
// eslint-disable-next-line
let planetssearchlist = this.state.planets.filter((planet) => {
if (planet.name) {
if (planet.name.toLowerCase().includes(e.target.value.toLowerCase())) {
return true;
}
}
});
this.setState({
filteredPlanets: planetssearchlist,
});
}
getPlanetInfo = (url) => {
this.setState({
isGettingPlanetInfo: true,
});
axios({
method: 'GET',
url: url,
})
.then((response) => {
console.log(response.data);
this.setState({
planetInfo: response.data,
isGettingPlanetInfo: false,
});
})
.catch((error) => {
this.setState({
isGettingPlanetInfo: false,
});
console.log(
"You've made an error with the planets load charles: ",
error
);
});
};
componentDidMount() {
axios({
method: 'GET',
url: 'https://swapi.dev/api/planets/',
})
.then((response) => {
console.log(response);
let planetslist = response.data.results;
this.setState({ planets: planetslist, filteredPlanets: planetslist });
})
.catch((error) => {
console.log(
"You've made an error with the planets load charles: ",
error
);
});
}
render() {
return (
<div>
<h1>Star Wars Planets</h1>
<form>
<input
placeholder='searchbar'
type='text'
onChange={this.handleChange}
/>
</form>
{this.state.filteredPlanets.map((planet, i) => (
<p onClick={() => this.getPlanetInfo(planet.url)} key={i}>
{planet.name}
</p>
))}
<hr />
{this.state.isGettingPlanetInfo ? (
<p>getting planet info...</p>
) : typeof this.state.planetInfo === 'object' &&
Object.keys(this.state.planetInfo).length ? (
<div>
<p>name: {this.state.planetInfo.name}</p>
<p>climate: {this.state.planetInfo.climate}</p>
<p>population: {this.state.planetInfo.population}</p>
</div>
) : (
''
)}
</div>
);
}
}
With react router
import React, { PureComponent } from "react";
import axios from "axios";
import { BrowserRouter, Route, Switch, Link } from "react-router-dom";
class PlanetInfo extends React.Component {
state = {
url: "",
planetInfo: {},
isGettingPlanetInfo: false
};
getPlanetInfo = () => {
this.setState({
isGettingPlanetInfo: true
});
axios({
method: "GET",
url: this.state.url
})
.then(response => {
console.log(response.data);
this.setState({
planetInfo: response.data,
isGettingPlanetInfo: false
});
})
.catch(error => {
this.setState({
isGettingPlanetInfo: false
});
console.log(
"You've made an error with the planets load charles: ",
error
);
});
};
componentDidMount = () => {
this.setState(
{
url: this.props.location.state.planet.url
},
this.getPlanetInfo
);
};
render() {
return (
<div>
{this.state.isGettingPlanetInfo ? (
<p>getting planet info...</p>
) : typeof this.state.planetInfo === "object" &&
Object.keys(this.state.planetInfo).length ? (
<div>
<p>name: {this.state.planetInfo.name}</p>
<p>climate: {this.state.planetInfo.climate}</p>
<p>population: {this.state.planetInfo.population}</p>
</div>
) : (
""
)}
</div>
);
}
}
class Home extends PureComponent {
constructor(props) {
super(props);
this.state = {
planets: [],
filteredPlanets: []
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
// eslint-disable-next-line
let planetssearchlist = this.state.planets.filter(planet => {
if (planet.name) {
if (planet.name.toLowerCase().includes(e.target.value.toLowerCase())) {
return true;
}
}
});
this.setState({
filteredPlanets: planetssearchlist
});
}
componentDidMount() {
axios({
method: "GET",
url: "https://swapi.dev/api/planets/"
})
.then(response => {
console.log(response);
let planetslist = response.data.results;
this.setState({ planets: planetslist, filteredPlanets: planetslist });
})
.catch(error => {
console.log(
"You've made an error with the planets load charles: ",
error
);
});
}
render() {
return (
<div>
<h1>Star Wars Planets</h1>
<form>
<input
placeholder="searchbar"
type="text"
onChange={this.handleChange}
/>
</form>
{this.state.filteredPlanets.map((planet, i) => (
<Link to={{ pathname: "/info", state: { planet: planet } }}>
<p key={i}>{planet.name}</p>
</Link>
))}
</div>
);
}
}
export default function Navigation() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/info" component={PlanetInfo} />
</Switch>
</BrowserRouter>
);
}