Memorizing values upon an async call in react - javascript

I'm trying to memorize some values in a react component because it's re rendering even when data hasn't changed (and wont change). Using useEffect + useState the data displays correctly, but the functions are triggered each time the component is re rendered. Currently am trying to implement the useMemo hook but the async call/promise is not resolving in the render process, so it doesn't even loads the data. I'll try to give the most information out of this:
This is my AppRouter component, i create the contract and pass it as value to a provider that will be used in some other components:
import { useWeb3React } from "#web3-react/core";
import React, { useEffect, useState } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { AdminScreen } from "../components/admin/AdminScreen";
import { ContractsContext } from "../components/ContractsContext";
import { Navbar } from "../components/ui/Navbar";
import { getLibrary } from "../helpers/web3Getters";
import { useCreateContract, useGetLibrary } from "../hooks.js/contractsHooks";
import { createContract } from "../web3-utils/contractCreation";
import { MarketRoutes } from "./MarketRoutes";
import { PrivateRoute } from "./PrivateRoute";
export const AppRouter = () => {
const context = useWeb3React();
//console.log("[1] context in app router: ", context);
const { contract: kolorTokenContract, loading: loadingContract } =
useCreateContract(
context,
"0x9414f981a5B5ef2bE455f2427E2166c35e8989fB",
"abis/KolorToken.json"
);
return (
//<p>{loadingLibrary ? "library ready" : "loading library"}</p>
<ContractsContext.Provider value={[kolorTokenContract]}>
<BrowserRouter>
<Navbar />
{/* Set private route for Admining nfts & tokens */}
<Routes>
<Route
path="/admin"
element={
<PrivateRoute>
<AdminScreen />
</PrivateRoute>
}
/>
<Route path="/*" element={<MarketRoutes />} />
</Routes>
</BrowserRouter>
</ContractsContext.Provider>
);
};
The contract is then obtained from my custom context in the admin route (which is what im testing now) and then passed to one of its children:
import React, { memo, useContext, useMemo } from "react";
import { getERC20Info } from "../../helpers/tokenGetters";
import { useGetERC20Info } from "../../hooks.js/contractsHooks";
import { ContractsContext } from "../ContractsContext";
export const TokenInfo = memo((tokenContract) => {
//const { _address: ERC20Address } = tokenContract;
const { address, owner, vault, supply } = useGetERC20Info(tokenContract);
//const result = useMemo(() => getERC20Info(tokenContract), [tokenContract]);
//console.log("contract from tokeninfo:", tokenContract);
//console.log("result: ", result);
return (
<div className="row align-items-center">
<div className="col-8 col-md-6 col-sm-4 ">Minting Form</div>
<div className="col-4 col-md-3 col-sm-2 animate__animated animate__fadeInRightBig">
<h2>Kolor Token Info</h2>
<p>
Address: <b>{address}</b>
</p>
<p>
Owner: <b>{owner}</b>
</p>
<p>
Vault: <b>{vault}</b>
</p>
<p>
Current supply: <b>{supply}</b>
</p>
</div>
<hr />
</div>
);
});
Actually i'm using a custom hook with useState and useEffect to fetch the data, but it re renders the TokenInfo component even when the tokenContract hasn't changed at all. This is my custom hook:
export const useGetERC20Info = (contract) => {
//console.log("contract from usegeterc20info effect: ", contract);
const [state, setState] = useState({
address: "loading...",
owner: "loading...",
vault: "loading...",
supply: "loading",
});
useEffect(() => {
getERC20Info(contract).then(({ address, owner, vault, supply }) => {
setState({
address,
owner,
vault,
supply,
});
return () => {
setState({});
};
});
}, [contract]);
return state;
};
My getERC20Info function, tries to fetch data from the blockchain, nothing wrong with that, its working fine:
export const getERC20Info = async (contract) => {
console.log("getting erc20 info...");
console.log("contract from geterc20info: ", contract);
const { _address: address } = contract;
const owner = await getERC20Owner(contract);
const vault = await getERC20Vault(contract);
const supply = await getERC20Supply(contract);
//console.log("supply: ", supply);
return {
address,
owner,
vault,
supply,
};
};
Thanks in advance for any help!

Related

my react-app refreshes while navigating and waste the data in the redux state [duplicate]

This question already has answers here:
How to use a element with href property in combination with react-router?
(2 answers)
Closed 4 months ago.
So my web app here is a small gift shop project and the probleme is when the user sign in everything goes very well and the user input are submitted to redux reducer after beeing validated with regex, and the homepage says hello {username} etc ...
the probleme is when the user navigate throught the app pages like clicking on a product to see the info about it and then click the browser back-button to go back to the homepage, the app refreshes and waste all the user input and i need to sign in again.
ive been working on this bug for 5 days HEEELP!!
This is App.js
import './App.css';
import Main from './components/main/main';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store';
import Items from './components/items/items';
import ProductInfo from './components/productInfo/productInfo';
import UserInterface from './components/userInterface/userInterface';
import Profile from './components/profile/profile';
function App() {
return (
<Provider store={store}>
<Router className="App">
<Routes>
<Route exact path='/' element={
<div id='Homepage'>
<Profile />
<Main />
<Items/>
</div>
}></Route>
<Route exact path='/product-info/:id' element={<ProductInfo/>}></Route>
<Route exact path='/user-form' element={<UserInterface/>}></Route>
</Routes>
</Router>
</Provider>
);
}
export default App;
This is Profile.js the component responsible to receive and display user data when needed.
import React, { Component } from 'react'
import './profile.css';
import { connect } from 'react-redux';
import { checkUser } from '../../actions/userActions';
class Profile extends Component {
state = {
user : {
isLoggedIn : false,
userName : '',
email : '',
password : ''
}
}
componentDidMount(){
this.props.checkUser()
const currentUser = this.props.user.user;
console.log(currentUser);
this.setState({
user : currentUser
})
}
render() {
const {user} = this.state;
//const {checkUser} = this.props;
return (
<div>
{user?.isLoggedIn ? <h2 id='welcome-user'>Welcome {user.userName}</h2> :
<a id="profile-area" href='/user-form'>
<img src="user.png" alt="profile" id="profile-img" />
</a>
}
</div>
)
}
}
const mapUserStateToProps = (state) => {
return{
user : state?.myUser
}
}
export default connect(mapUserStateToProps, {checkUser})(Profile);
This is userInterface.js the sign in form that take user input and submit it to redux reducer state.
import React from 'react'
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router';
import { getUser } from '../../actions/userActions';
import { connect } from 'react-redux';
import './userInterface.css';
function UserInterface(props) {
const [userInfo, setUserInfo] = useState({
isLoggedIn : false,
userName : '',
email : '',
password : ''
})
const navigate = useNavigate();
let alertMsg = '';
const getInputToState = (e,inputField) => {
switch(inputField){
case 'username' : {
setUserInfo(userInfo.userName = e.target.value);
const newUserInfo = userInfo; // create new state object
setUserInfo(newUserInfo);
console.log(userInfo);
break
}
case 'email' : {
setUserInfo(userInfo.email = e.target.value);
const newUserInfo = userInfo; // create new state object
setUserInfo(newUserInfo);
console.log(userInfo);
break
}
case 'password' : {
setUserInfo(userInfo.password = e.target.value) ;
const newUserInfo = userInfo; // create new state object
setUserInfo(newUserInfo);
console.log(userInfo);
break
}
default:
return null
}
}
const onSubmit = (e) => {
e.preventDefault();
let namePattern = /[A-Za-z0-9]{3,16}./ ;
let emailPattern = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/ ;
if(userInfo.userName?.match(namePattern) && userInfo.email?.match(emailPattern) && userInfo.password.length >= 8){
setUserInfo(userInfo.isLoggedIn = true);
props.getUser(userInfo);
navigate("/");
}else{
document.querySelector('#alert-msg').innerText = 'username, email or password are invalid';
}
}
return (
<div id='user-div'>
<form id='user-form'>
<h2 id="form-title">Tell us who you are :)</h2>
<ul id="form-inputs">
<li className="form-input">
<input type="text" className="user-input" placeholder='Enter a username' maxLength={16} onChange={(e) => getInputToState(e, "username")}/>
</li>
<li className="form-input">
<input type="text" className="user-input" placeholder='Enter your e-mail' onChange={(e) => getInputToState(e, "email")}/>
</li>
<li className="form-input">
<input type="text" className="user-input" placeholder='Create a password' onChange={(e) => getInputToState(e, "password")}/>
</li>
<li className="form-input">
<a><button className='action-form' id='submit-button' onClick={onSubmit}>Submit</button></a>
</li>
</ul>
<h4 id='alert-msg' ></h4>
<h3 id='login-sign'>Already have an account ? <a href="/" id='login-form'>Log In</a></h3>
</form>
</div>
)
}
const mapStateToProps = (state) => {
return {
myUser : state?.usersReducer
}
}
export default connect(mapStateToProps, {getUser})(UserInterface) ;
And finally the userReducer.js
const initialState = {
user : {
isLoggedIn : false,
userName : '',
email : '',
password : ''
}
};
export default function(state = initialState, action){
switch(action.type){
case 'GET_USER':
initialState.user = action.payload;
case 'CHECK_USER':
return{
...state
}
default:
return state
}
}
I guess these are all the components you need to help me.
Thank you in advance :)
It's because you are using plain HTML <a> tag to navigate to other pages, which triggers the default browser navigation causing the refresh.
You have to use the Link component from the react-router library (see https://reactrouter.com/en/main/components/link) in order to navigate to another page without refreshing.

how do i delay rendering of a page until my data is available?

I have an issue where my page is trying to render before the data is available. I have async awaits in place, however, the page gets an error saying data is undefined. When I comment out my page elements and check react dev tools I can see the data object in full, so I know the data request is working.
I need to put in a check for the data and if present then render but as a new developer I am not sure how to implement this in my code.
import React, { useEffect, useState } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { getDoc, doc } from "firebase/firestore";
import { db } from "../api/auth/firebase/config";
import Head from "next/head";
import ArtistHeader from "../../components/ArtistHeader";
import UploadButton from "../../components/UploadButton";
import styles from "../../styles/artistPage.module.css";
export default function Artist() {
const { data: session, status, loading } = useSession();
const [artist, setArtist] = useState();
const router = useRouter();
const artistId = router.query.artistId;
const fetchArtist = async () => {
const artistRef = doc(db, "users", `${artistId}`);
const docSnap = await getDoc(artistRef);
setArtist(docSnap.data());
};
useEffect(() => {
if (!router.isReady) return;
console.log(artistId);
if (status === "unauthenticated") {
router.push("/auth/signin");
}
fetchArtist();
}, [status, loading, router]);
return (
<section className={styles.wrapper}>
<Head>
<title>{artist.screenName}</title>
</Head>
<div className={styles.artistPage}>
<ArtistHeader artist={artist} />
<div className={styles.songContainer}>
<UploadButton />
</div>
</div>
</section>
);
}
Thanks in advance for help.
use optional chaining. This will prevent you from getting undefined error.
see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
On the other hand you can do the following:
const [isLoading, setIsLoading] = useState(false)
const [isError, setIsError] = useState(false)
const fetchArtist = async () => {
setIsLoading(true)
const artistRef = doc(db, "users", `${artistId}`);
try{
const docSnap = await getDoc(artistRef);
setArtist(docSnap.data());
}catch(e){
setIsError(true)
}
setIsLoading(false)
};
if(isLoading && !artist){
return (
<h2>Loading...</h2>
)
}
if(!isLoading && isError){
return (
<h2>Something went wrong</h2>
)
}
return (
<section className={styles.wrapper}>
<Head>
<title>{artist?.screenName}</title>
</Head>
<div className={styles.artistPage}>
<ArtistHeader artist={artist} />
<div className={styles.songContainer}>
<UploadButton />
</div>
</div>
</section>
)
But I would prefer react-query for server state management. It handles all your loading | revalidation | caching and more.
Check out https://tanstack.com/query/v4/docs/adapters/react-query
Let's make it simple with useQuery hook from react-query
import { useQuery } from '#tanstack/react-query'
const fetchArtist = async (artistId: string) => {
const artistRef = doc(db, "users", `${artistId}`);
return getDoc(artistRef);
};
function Artist() {
const query = useQuery(['artist', artistId], fetchArtist)
const {isLoading, isError, data} = query
if(isLoading){
return (
<h2>Loading...</h2>
)
}
if(isError && !data){
return (
<h2>Something went wrong</h2>
)
}
return (
<section className={styles.wrapper}>
<Head>
{/* optional chaining (?.) */}
<title>{data?.artist?.screenName}</title>
</Head>
<div className={styles.artistPage}>
<ArtistHeader artist={data?.artist} />
<div className={styles.songContainer}>
<UploadButton />
</div>
</div>
</section>
)
}
// _app.jsx
import { Hydrate, QueryClient, QueryClientProvider } from '#tanstack/react-query'
export default function MyApp({ Component, pageProps }) {
const [queryClient] = React.useState(() => new QueryClient())
return (
<QueryClientProvider client={queryClient}>
<Hydrate state={pageProps.dehydratedState}>
<Component {...pageProps} />
</Hydrate>
</QueryClientProvider>
)
}
You can use getServerSideProps to call API on the server. Whenever data is ready, the page will start loading on the client-side.
import React, { useEffect, useState } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { getDoc, doc } from "firebase/firestore";
import { db } from "../api/auth/firebase/config";
import Head from "next/head";
import ArtistHeader from "../../components/ArtistHeader";
import UploadButton from "../../components/UploadButton";
import styles from "../../styles/artistPage.module.css";
export default function Artist({ data }) {
const { data: session, status, loading } = useSession();
const artist = data; //get data from the server
const router = useRouter();
useEffect(() => {
if (status === "unauthenticated") {
router.push("/auth/signin");
}
}, [status, loading, router]);
return (
<section className={styles.wrapper}>
<Head>
<title>{artist.screenName}</title>
</Head>
<div className={styles.artistPage}>
<ArtistHeader artist={artist} />
<div className={styles.songContainer}>
<UploadButton />
</div>
</div>
</section>
);
}
export async function getServerSideProps(context) {
const artistId = context.params.artistId;
const artistRef = doc(db, "users", `${artistId}`);
const docSnap = await getDoc(artistRef);
const data = docSnap.data();
return { props: { data: data || null } }
}
You can use a state isLoading. The initial value of isLoading will be false. Inside useEffect before fetching data set isLoading value as true and after completing fetching set isLoading as false. Now use conditional rendering if isLoading then render a Loader component else render jsx with data.

Unable to prevent flashing unauthorized content in next.js before redirecting to a route

import JoinComponent from '#/components/join/JoinComponent'
import Footer from '#/components/Layouts/Footer'
import GuestLayout from '#/components/Layouts/GuestLayout'
import Navbar from '#/components/Layouts/Navbar'
import { useAuth } from '#/hooks/auth'
import { useRouter } from 'next/router'
const Join = () => {
const router = useRouter()
const { user } = useAuth({
middleware: 'guest',
redirectIfAuthenticated: '/',
})
if (user !== undefined) {
return (
<GuestLayout>
<title>Join</title>
<div></div>
</GuestLayout>
)
} else {
return (
<GuestLayout>
<title>Join</title>
<Navbar />
<JoinComponent />
<Footer />{' '}
</GuestLayout>
)
}
}
export default Join
It is supposed to conditionally render the layouts if the user is authenticated but it still renders the else part for a brief amount of time and then redirects to '/'.
I am unable to figure out why this is the case.
import JoinComponent from '#/components/join/JoinComponent'
import Footer from '#/components/Layouts/Footer'
import Navbar from '#/components/Layouts/Navbar'
import Loader from '#/components/Loader'
import { useAuth } from '#/hooks/auth'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
const Join = () => {
const [loading, setLoading] = useState(true)
const { user } = useAuth({
middleware: 'guest',
redirectIfAuthenticated: '/',
})
useEffect(() => {
console.log(user)
if (user) {
setLoading(true)
}
let t
if (user === undefined) {
t = setInterval(() => {
setLoading(false)
}, 2000)
}
return () => {
clearInterval(t)
}
}, [user])
return (
<div>
<title>Join</title>
<Navbar />
{loading ? <Loader /> : <JoinComponent />}
<Footer />{' '}
</div>
)
}
export default Join
Although my code have changed significantly over time but I have solved the issue in this manner.
What is important to note that for a certain time the useAuth hook doesn't return a user instance and in that period the user remains undefined.
Later if the user is already authenticated a user object is returned, otherwise user remains undefined.
In this case, it is difficult to know immediately if the user object will be defined, therefore we have to wait for some time before setting the loading state to false.
In this way a sudden flash of the undesired component can be prevented and instead a loader can be rendered.
However, the problem may arise in the future if the useAuth hook takes more time to return a user object than the hard coded time, that calls for another approach to this problem.

Link outside a Router Error, while everything set up properly

Ok, I have no idea why this is not working. Everything is set up properly from what I can see.
I am using "react-router-dom": "^5.0.0"
The code also uses the Tabulator grid library, specifically the React implementation of it. It's not really relevant, just wanted to note it.
The code works 100% without using the sub-component links, so the problem is not there.
The grid generator in Journals creates a table, which has link cells, which lead to the Journal component.
The link component is generated fine, it just doesn't work for reasons I don't know.
CodeSandbox
If you comment out the formatter line in columns in the Journal component, the app works again.
App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Header from './components/layout/Header';
import Dashboard from './components/pages/Dashboard';
import Journals from './components/pages/Journals';
import Journal from './components/pages/Journal';
class App extends Component {
render() {
return (
<Router>
<div className="App">
<div className="container">
<Header />
<div className="content">
<Route exact path="/" component={Dashboard} />
<Route exact path="/journals" component={Journals} />
<Route path="/journals/:key" component={Journal} /> // <------ ROUTE IS HERE
</div>
</div>
</div>
</Router>
);
}
}
export default App;
Journals.js
import React, { useState, useEffect } from "react";
import { Link } from 'react-router-dom';
import { ReactTabulator } from 'react-tabulator'
import "tabulator-tables/dist/css/tabulator.min.css";
import { reactFormatter } from 'react-tabulator';
function Journals() {
const [journals, setJournals] = useState([]);
useEffect(() => {
fetch("http://localhost:4000/journals")
.then(res => res.json())
.then(data => {
setJournals(data)
})
.catch(err => err);
}, []);
const JournalLink = (props) => {
const cellData = props.cell._cell.row.data;
let key = cellData.key_
let link = `/journals/${key}`
return <Link to={link}>{key}</Link>; // <------ LINK COMPONENT IS HERE
}
const columns = [
{
title: "Number",
field: "key_",
formatter: reactFormatter(<JournalLink />) // <------ LINK COMPONENT USED HERE
},
{ title: "Date", field: "date_" },
];
return (
<div>
<h1>Journals</h1>
<ReactTabulator
data={journals}
columns={columns}
tooltips={true}
layout={"fitData"}
/>
</div >
)
}
export default Journals;
reactFormatter usage example
reactFormatter definition
Journal.js
import React, { useState, useEffect } from "react";
import { ReactTabulator } from 'react-tabulator'
import "tabulator-tables/dist/css/tabulator.min.css";
function Journal(props) {
const [journalItems, setJournalItems] = useState([]);
const initialFormJournalItems = {
id: "",
journalId: "",
companyId: "",
documentKey: "",
documentDate: "",
debitAccount: "",
debit: "",
creditAccount: "",
credit: ""
}
const [formJournalItems, setFormJournalItems] = useState(initialFormJournalItems);
useEffect(() => {
fetch(`http://localhost:4000/journals/${props.match.params.key}`)
.then(res => res.json())
.then(data => {
setJournalItems(data)
})
.catch(err => err);
}, []);
const columns = [
{ title: "Document", field: "documentKey" },
{ title: "Date", field: "documentDate" },
];
return (
<div>
<h1>Journal</h1>
<ReactTabulator
data={journalItems}
columns={columns}
tooltips={true}
layout={"fitData"}
/>
</div >
)
}
export default Journal;
react-tabulator reFormatter is incompatible with react-router library.
https://github.com/ngduc/react-tabulator/blob/0.10.3/lib/Utils.js#L30
From source code,
function reactFormatter(JSX) {
return function customFormatter(cell, formatterParams, onRendered) {
//cell - the cell component
//formatterParams - parameters set for the column
//onRendered - function to call when the formatter has been rendered
onRendered(function () {
var cellEl = cell.getElement();
var CompWithMoreProps = React.cloneElement(JSX, { cell: cell });
react_dom_1.render(CompWithMoreProps, cellEl.querySelector('.formatterCell'));
});
return '<div class="formatterCell"></div>';
};
}
rendering of a formatted element uses the ReactDOM.render function to render the formatted element directly to DOM isolated from parent elements.
A fix to react-tabulator needs to be done to support this use case. One way to go is to have customFormatter return a custom component that provides a way to set its state from outside it. Then onRendered can call this function to set cell.

retrieve job details by job id using redux and axios

I have a jobs list. I have to retrieve a job details by passing 'jobid' as a paramater using axios. i have created action and reducer for that and connect to that my component. api is getting called but in jobid it is showing undefined. I think it is route problem. Please suggest me where to defined that and how to get the details.
My api is like(ex: 'http://localhost:3000/app/jobs/87938'). Here jobid is 87938. There are multiple job with different job id in my job list. Problem is how to define the jobid and passing to the api to retrieve the details of job
action code:
export const retrieveLocations = (jobId) => (dispatch) => {
axios.get(retrieveUrl+'/jobs/'+jobId).then(res => {
dispatch({
type: RETRIEVE_LOCATION,
payload: res.data.job.basicDetails
});
});
};
reducer code:
case 'RETRIEVE_LOCATION':
return{
...state,
conLocations:action.payload
}
component code:
class ConfiguredLocation extends React.Component{
constructor(props){
super(props);
this.handleRemove = this.handleRemove.bind(this);
this.clearall = this.clearall.bind(this);
}
handleRemove(mruCode){
this.props.removeLocation(mruCode)
}
clearall (){
this.props.removeAllLocation()
}
componentDidUpdate(prevProps){
let currJobId = this.props.match.params.jobId;
let prevJobId = prevProps.match.params.jobId;
if(currJobId!==prevJobId){
this.props.retrieveLocations(jobId);
}
}
componentDidMount(){
let {jobId} = this.props.match.params;
this.props.retrieveLocations(jobId);
}
render(){
const _labels = store.getLabels();
const {conLocations} = this.props;
return(
<div className="col-padding">
<div className="pos-div"><h3>Configured Location</h3><button className="allLargeBtn" onClick={()=>{this.clearall()}}>Remove all location</button></div><hr/>
<table className="table">
<tbody>
{conLocations.map((loct,index)=><tr key={index}>
<td><h5>{loct.mruCode} - {_labels[loct.division]} - {loct.country}</h5></td>
<td className="text-right"><img alt="DeleteIcon" onClick={()=>this.handleRemove(loct.mruCode)}className="deleteIconStyle" src="img/delete_large_active.png" /></td>
</tr>
)}
</tbody>
</table>
</div>
);
}
}
const mapStateToProps = state =>{
return {
conLocations: state.locationRed.conLocations
};
};
const mapDispatchToProps = (dispatch) =>{
return{
removeLocation: (mruCode)=>{dispatch(removeLocation(mruCode))},
removeAllLocation: () =>{dispatch(removeAllLocation())},
retrieveLocations:(jobId) =>{dispatch(retrieveLocations(jobId))}
};
};
export default connect(mapStateToProps,mapDispatchToProps)(withRouter(ConfiguredLocation));
router code(appnavigator - i am not able to define job id here. Please suggest me on this)
import React from 'react';
import ReactDOM from 'react-dom';
import {Router, Route} from 'react-router-dom';
import { Security, ImplicitCallback, SecureRoute } from '#okta/okta-react';
import history from '../history';
import store from '../stores/store';
import ConfiguredLocation from '../components/location/ConfiguredLocation';
class AppNavigator extends React.Component {
constructor( props ) {
super( props );
this.state = {
loading: true
};
}
componentDidMount() {
var self = this;
setTimeout(() => {
self.setState({ loading: false });
}, 1000);
}
render() {
if (this.state.loading) {
return (
<div className="fix"><i className="fa fa-2x fa-circle fa-spin"></i>
<div>Loading</div>
</div>
)
} else {
return (
<Router history={history}>
<Security issuer={Something..}
client_id={something...}
redirect_uri={window.location.origin + '/app/callback'}
scope={['profile', 'openid']}>
<Route path='/callback' component={ImplicitCallback} />
<AppFrame />
</Security>
<Route exact path= '/jobs/:jobId' component={ConfiguredLocation}
</Router>
);
}
}
};
store code:(where appnavigator called)
<Provider store={createStoreWithMiddleware(reducers)}>
<AppNavigator />
</Provider>
Everything is working fine. If i call the api without parameter. it is working fine. So i am not able to route the parameter properly. Please help me on this.
l.png
All your code is correct after editing. When you want to generate dynamic route, like jobId in /app/jobs/87938 route, first you should write this route in router file like this:
<Route exact path="/app/jobs/:jobId" component={ConfiguredLocation}/>
after that, When open http://localhost:3000/app/jobs/87938 route your jobId is 87938 and you can get it in your componentDidMount lifecycle:
componentDidMount() {
const {jobId} = this.props.match.params;
this.props.retrieveLocations(jobId);
}
Demo:

Categories