I have index.js like this
var hist = createBrowserHistory();
ReactDOM.render(
<Router history={hist}>
<Switch>
<Route path="/landing" component={LandingPage} />
<Route path="/" component={Components} />
</Switch>
</Router>,
document.getElementById("root")
);
At first, User opens the landing page and then go to / page.
in Landing page ,there is a button to move
<Button
variant="contained"
color="secondary"
style={{margin:"50px"}} href="/">
go next
</Button>
However here I want to move / page with POST parameters
id=12
name=myname
from=landing
At first I tried with GET parameter /?id=12&name=myname&from=landing
I can't use useQuery in class Component. I am not familiar with function component so mainly use 'class component`
How can I make this???
Or is there any good way to give the parameters when switching another page without POST nor GET?
I appreciate your help.
You can use window.location.search API, just put following function into a JS file and import it where you need:
src/utils/query.js
export function getQuery() {
let b = window.location.search
.slice(1)
.split("&")
.map(qStr => qStr.split("="))
.reduce((acc, inc) => {
acc[inc[0]] = inc[1];
return acc;
}, {});
return b;
}
and where you want to use it
import getQuery from './utils/query';
.
.
.
let q = getQuery();
if(q.lenght){
let name = q['name']
let id = q['id']
let from = q['from']
}
//Or directly call it
let name = getQuery()['name']
let id = getQuery()['id']
let from = getQuery()['from']
Related
Working on a little project of mine but ran into an issue while working with the so called Context API. First time doing it as well.
The issue I am having is that I am unable to console.log the data I am setting. Now I am trying to make a "Add To Cart" button, and whenever the button is pressed. An object containing things such as name, price, color etc will be sent over to my ShoppingCart component.
I am able to set the value, whenever I press the button. And it appears in the console.log. Though, I am unable to console.log the value from ShoppingCart.
My files look like this:
./Contexts
./AddToCartContext.js
./Components
./Product
./ProductContent.js // Here the "add to cart" button is located.
./ShoppingCart
./ShoppingCart.js // Here I need the data from ProductContent.js
App.js
Here is my App.js code:
const [cartItems, setCartItems] = useState({});
console.log(cartItems); // The data is being logged here perfectly.
return (
<AddToCartContext.Provider value={{ cartItems, setCartItems }}>
<ThemeProvider theme={themeMode}>
{/* GlobalStyles skapas i ./themes.js */}
<GlobalStyles />
<Router>
<Route exact path="/cart">
<ShoppingCart theme={theme} toggleTheme={toggleTheme} />
</Route>
<Route exact path="/category/:type/:id/:productid">
<FetchAPI />
</Route>
// ...
</Router>
</ThemeProvider>
</AddToCartContext.Provider>
);
Here is my shoppingcart.js code:
import { AddToCartContext } from "../../Contexts/AddToCartContext";
const ShoppingCart = (props) => {
const { cartItems } = useContext(AddToCartContext);
console.log(cartItems); // This always result in an empty Object.
return (
<Fragment>
<TopNavigation />
<BottomNavigation theme={props.theme} toggleTheme={props.toggleTheme} />
<Cart />
<Footer />
</Fragment>
);
};
And here is the code in ProductContent.js (shorten as its pretty long):
import { AddToCartContext } from "../../Contexts/AddToCartContext";
const ProductContent = (props) => {
const { setCartItems } = useContext(AddToCartContext);
return (
<button
type="button"
onClick={() =>
setCartItems({ // This returns the object to App.js, but not Shoppingcart.js
name: props.name,
price: props.price,
color: props.mainImg?.colour,
img: props.mainImg?.url,
id: params.productid,
})
}
className={classes.add_to_cart}
>
<Cart />
add to cart
</button>
);
}
As mentioned, it's the first time I work with Context API. Am I missing anything?
EDIT:
Did some testing, and if I set the initial value on const [cartItems, setCartItems] = useState({}); to for example "test", then it is being rendered inside of the Cart page.
Nothing is logging inside of the cart upon the button press. But whenever the initial value is set to "test" it is loaded instantly.
Here is the code for creating the context (AddToCartContext.js):
import { createContext } from "react";
export const AddToCartContext = createContext({});
try without destructuring like this below
const cartItems = useContext(AddToCartContext);
console.log(cartItems);
and check if there is anything in that object
I have been working on an inventory management system built in ReactJS with a back-end MariaDB database. The architecture includes user registration and logon modules with JWT authentication, a simple dashboard using D3, an inventory display screen using the React-Data-Table-Component, and an add inventory module. I will use the add-inventory module in the edit-inventory functionality by passing in a parameter to differentiate between add or edit mode (I have not yet implemented that parameter). A user can click on a row on the inventory display screen to pull that record up in edit mode, but currently I am not getting to the page to allow for inventory edit.
My code (inventorylist.component.jsx) looks like this:
updateRecord = row => {
this.setState({
...this.state,
selectedRow: row,
editSelectedRow: true
}, () => {
console.log('UPDATED STATE:',this.state.selectedRow)
})
}
editRecord = (event) => {
event.preventDefault();
return <Link to='/add' />
//return <Redirect to='/add' />
// return (
// <>
// <Router>
// <Switch>
// <Route path='/add' component={AddInventory} />
// </Switch>
// </Router>
// </>
// )
}
render() {
const inventoryTitle = this.props.jwt.username + "'s Inventory"
return (
<>
<DataTable
title={inventoryTitle}
striped={true}
highlightOnHover={true}
fixedHeader={true}
pagination={true}
paginationPerPage={10}
onRowClicked={this.updateRecord}
columns={columns}
data={this.state.inventory}
/>
<button type='button' onClick={this.editRecord}>Edit</button>
</>
)
}
This is not navigating to the add-inventory component. I have put a console.log into the editRecord function to verify that it is getting into that function after clicking on the button, but that's as far as it seems to be going.
I'm sure I'm just missing something fairly obvious here, but does anyone have any suggestions?
You can use history object to navigate imperatively:
history.push(<path>);
Read more about history
The problem is that you are return a Link which is a JSX element. What you need to do is one of the following:
If you want to keep the button element, you can push a new route into the history like this: history.push('/edit')
If you want to use Link, you need to replace you button with it and, when you click the link, it will automatically navigate there
With Hooks
If you were using hooks, you could use the useHistory hook provided by react-router to navigate to a different route doing something like this:
const history = useHistory();
const editRecord = () => {
history.push('/app');
};
i am building a project, in which when user click the buyNow button in Basket (child 2) it will pass the props back to parent where it further pass it to another child in Signin(child 3) where we call an API call(inside useEffect) to update the mysql database but it seems that the API call is called twice as in database two records are being created and in front end i got two identical invoices record but different file names.
Any suggestion guys why i am facing this, please note if i remove the useEffect statement from the Signin it will then continuously non-stop call the API call so i think i cant remove the useEffect, other then this i cant see why it is happening. any suggestion please.
Main (APP)___|
|_Child 1(Home)
|_Child 2 (Basket)
|_Child 3 (signin)(API triggers here)---Sub Child 3-1 (useraccount)
Update-1: After removing the strictMode it does solve the issue, but does it means if i temporarily fixed the issue or if i have to use the stricMode and find the real problem
Child 2- Basket- Customer press the buyNow button and it triggers resetBasket function
const buyNow = (basketItems) => {
resetBasket(basketItems);
window.location.href = "http://localhost:3000/signin";
};
<ButtonGroup aria-label="quantityofproduct">
<Button variant="secondary" name="subtract" value="subtract" onClick={() => buyNow(basketItems)}>
Buy Now
</Button>
</ButtonGroup>
Main App resetBasket takes the basketitems and pass to parent element
const [finalBuy, setfinalBuy] = useState(finalbuyitems());
const resetBasket = (basketItems) => {
setfinalBuy(basketItems);
window.localStorage.setItem("user-final", JSON.stringify(basketItems));
}
<Route
path="/basket"
exact
render={(props) => (
<Basket {...props} userData={userData} userstatus={siginalready} basketItems={basketItems} updatedBasket={updatedBasket} resetBasket={resetBasket} />
)}
/>
<Route
path="/signin"
exact
render={(props) => <Signin {...props} buyNow={buyNow} resetBuynow={resetBuynow} userData={userData} finalBuy={finalBuy} userstatus={siginalready} />}
/>
Child 3 - Signin ,here we call the API call(using useEffect) and update the Mysql server and recieve the invoice in PDf format from backend
const [allInvoices, setallInvoices] = useState([]);
// The API call in the useEffect is triggering twice and thats why i am getting two invoices and two record at backend
useEffect(() => {
const headers = new Headers();
headers.append("content-type", "application/json");
const options = {
method: "POST",
headers,
credentials: "include",
body: JSON.stringify(),
};
const newRequest = new Request("http://localhost:5000/api/invoice-all", options);
(async () => {
const invoiceFetch = await fetch(newRequest)
.then((data) => {
return data.json();
})
.then((data1) => {
setallInvoices(data1);
})
.catch();
})();
// }, []);
return <div>{userstatus ? <Useraccount userinfo={userData} userstatus={userstatus} finalBuy={finalBuy} allInvoices={allInvoices} /> : <SigninOptions />}</div>;
Sub Child-Useraccount then it display the items recieved from the backend-mysql nodejs
// here the return is showing two different invoices of same items bought i.e two times the API is being called
return (
allInvoices.map((eachInvoice, index) => {
........................................})
I think the <React.StrictMode> is causing double execution. Please take a look after removing it from your top level component.
Please refer This Link for more details on StrictMode double execution.
I am facing an issue while passing the state to the child component, so basically I am getting customer info from child1(Home) and saving in the parent state(App) and it works fine.
And then I am passing the updated state(basketItems) to child2(Basket). But when I click on the Basket button the basket page doesn't show any info in console.log(basketItems) inside the basket page and the chrome browser(console) looks refreshed too.
Any suggestion why it is happening and how can I optimize to pass the data to child2(basket) from main (APP).
update:2
i have tired to simulated the code issue in sand box with the link below, really appreciate for any advise about my code in codesandbox (to make it better) as this is the first time i have used it
codesandbox
Update:1
i have made a small clip on youtube just to understand the issue i am facing
basketItems goes back to initial state
Main (APP)___|
|_Child 1(Home)
|_Child 2 (Basket)
Snippet from Parent main(App) component
function App() {
const [basketItems, setBasketItems] = useState([]);
const addBasketitems = (product, quantity) => {
setBasketItems(prevItems => [...prevItems, { ...product, quantity }])
}
console.log(basketItems) // here i can see the updated basketItems having customer data as expected [{...}]
return (
<Router>
<div className="App">
<header className="header">
<Nav userinfo={userData} userstatus={siginalready} />
</header>
<Switch>
<Route path="/" exact render={(props) => (
<Home {...props} userData={userData} userstatus={siginalready}
addBasketitems={addBasketitems}
/>
)}
/>
<Route path="/basket" exact render={(props) =>
(<Basket {...props} basketItems={basketItems} />
)}
/>
</Switch>
</div>
</Router>
Snippet from the child(basket)
function Basket({basketItems}) {
console.log(basketItems) // here i only get the [] and not the cusotmer data from parent component
return (
<div>
{`${basketItems}`} // here output is blank
</div>
);
}
export default Basket;
Snippet from the child(Home)
... here once the button is pressed it will pass the userselected details to parent
....
<Button name={producNumber} value={quantities[productName]} variant="primary"
onClick={() => {
addBasketitems(eachproduct, quantities[productName])
}}>
Add to Basket
</Button >
Your function works fine, the reason your output in addbasketItem does not change is the when using setState it takes some time to apply the changes and if you use code below you can see the result.
useEffect(()=>{
console.log('basket:',basketItems)
},[basketItems])
Your Basket component only renders once so replace it with this code and see if it works:
function Basket({ basketItems }) {
const [items, setItems] = useState([]);
useEffect(() => {
setItems(basketItems);
}, [basketItems]);
return <div>{`${items}`}</div>;
}
but for passing data between several components, I strongly suggest that you use provided it is much better.
I have this App.jsx that has the routing and I have a component NextPage.jsx that is a simple Link that should point to the next page. My issue is:how can I tell to the link in NextPage component to point to the next page? so if I am in Homepage the link should let me go to Portfolio, if on Portfolio I should be able to go to Skills and so on.
This is my App.jsx
const App = () => (
<div className="main-container">
<Menu/>
<NextPage/>
<AnimatedSwitch
atEnter={{ offset: 100}}
atLeave={{ offset: -100}}
atActive={{offset: 0}}
mapStyles={(style) => ({
transform: `translateX(${style.offset}%)`,
})}
>
<Route exact path="/" component={Homepage} />
<Route path="/portfolio" component={Portfolio} />
<Route path="/skills" component={Skills} />
<Route path="/contacts" component={Contacts} />
<Route path='*' component={NotFound} />
</AnimatedSwitch>
</div>
);
export default App;
This is my NextPage.jsx
const NextPage = () => (
<div className="next-arrow">
<Link to='#HEREGOESTHENEXTPAGELINK#'><i className="fa fa-angle-right" aria-hidden="true"></i></Link>
</div>
);
export default NextPage;
Your approach to implementing this seems a bit odd in my opinion, but I digress.
The first thing you'd need to do is to somehow store all the links as well as their order of appearance. The biggest question I'd say is where you're going to store this; you could store it in a database, create a global variable, store it in a stage-management library (if you use one), etc etc.
It is unclear which of these you use and which you'd prefer, so I'll leave that to you and just present the concept below.
In your root React Component define an array of all the links. You could do this in the constructor:
class MyApp extends React.Component {
constructor() {
super();
window.links = ["/", "/portfolio", "/skills", "/contacts"];
}
render() ...
}
This will make window.links accessible in all components. This means you compare the active url, look it up in the array, and make the link direct you to the next one.
const NextPage = (props) => {
let idx = window.links.indexOf(props.route.path) + 1;
let link = (idx == window.links.length) ? window.links[0] : window.links[idx];
return (
<div className="next-arrow">
<Link to={link}><i className="fa fa-angle-right" aria-hidden="true"></i></Link>
</div>
);
}
export default NextPage;
Note that if the current link is not one of the ones defined in window.links, the link will take you to the first one.