I have this app, where i want to display an logout button in the navigation when the user is logged in. But for some reason, the button only shows after i do a refresh of the page, not when the user is logged in.
Also the same thing happens for the cart number update (on the same component), it only update the number after a refresh. Here i am trying to get number from local storage. I made a seperat component for the "buy" button since i want it on all items.
I need some help please, what am i doing wrong?
Here is Navigation component:
function Navigation() {
const [loggedIn, setLoggedIn] = useState(JSON.parse(localStorage.getItem("games")));
let history = useHistory();
function logOut() {
localStorage.clear('Email', 'Password');
history.push('/')
}
function getCartItems() {
if (localStorage.getItem("games")) {
return JSON.parse(localStorage.getItem("games")).length
}
else {
return 0;
}
};
return (
<div className="navgation_container">
<div className="navigation_cartcontainer">
<img className="navigation_logo" src={logo} alt="logog bits&bots" />
{loggedIn ? (
<div className="navigation_cartimg">
<img className="navigation_cart" src={cart} alt="cart for the page" />
<p className="navigation_numberitems">{getCartItems()}</p>
<button className="navigation_logout" onClick={logOut}>Log out</button>
</div>
) : (
<div>Test</div>
)}
</div>
</div>
);
}
Using useState might help you and pass in the value from local storage to useState as shown :
useEffect( ()=>{
setLoggedIn(data_from_local_storage);
}[data_from_local_storage]);
Related
so i'm creating my first fullstack website and once a user signs in it gets stored in the localStorage and i want to display the name of the user in my header once he is logged in but my header is not re rendering so nothing happens : this is the header before logging in
header
and this is how i want it to Be after signing in :
header after logging in this is my Layout code:
import "../assets/sass/categoriesbar.scss";
import Header from "./Header/Header";
const Layout = (props) => {
return (
<>
<Header/>
<main>
{ props.children}
</main>
</>
);
}
export default Layout;
and this is the toolBar in my Header :
const ToolBar = () => {
const history = useHistory();
let currentUser= JSON.parse(localStorage.getItem("user-info"));
const logoutHandler = () => {
localStorage.clear("user-info");
history.push("/login");
};
return (
<>
<div className={classes.NavigationBar}>
<h1>
<Link to="/">Pharmashop</Link>
</h1>
<NavLinks logout={logoutHandler}/>
{localStorage.getItem("user-info")?
<h5>Welcome {currentUser.name} !</h5>
:
<RegisterButton />
}
</div>
</>
);
};
export default ToolBar;
please help me it's frustrating
PS: this is my first stackoverflow question sorry if it's unorganized and unclear and sorry for my bad english.
Hazem, welcome to Stack Overflow.
In react, if you want the component to re-render when some data changes, that info must be in the component state. In your code the current user is a const, not bind to the component's state. This is how it could auto re-render when the user logs in:
const ToolBar = () => {
const [currentUser, setCurrentUser] = useState(JSON.parse(localStorage.getItem("user-info")));
const logoutHandler = () => {
localStorage.clear("user-info");
history.push("/login");
};
return (
<>
<div className={classes.NavigationBar}>
<h1>
<Link to="/">Pharmashop</Link>
</h1>
<NavLinks logout={logoutHandler}/>
{currentUser?
<h5>Welcome {currentUser.name} !</h5>
:
<RegisterButton />
}
</div>
</>
);
};
export default ToolBar;
See more about state in the official documentation.
I have an item and when I click on more info button a modal window with description appears but there is no endpoint like /modal in current route cause it's not external page I redirect to.
So in my modal window I have make a bid button and I can set a price in case I'm logged in.
otherwise Modal window with login form should appear with a request to log in.
This modal is on my navBar that is fixed whether I'm on current page or another one.
So how to pass this Modal Log in using function from another component ?
Here is my Modal with item description:
const ModalDetails = (props) => {
console.log(props, ' for modal')
const [loggedIn, setLoggedIn] = useState(false)
const checkUser = () => {
if (!loggedIn) {
/// how to pass that path to log in modal??
}
}
return (
{ item.typeSale == 'auction' && <button className='btn-item auction-btn-bet'
onClick={checkUser}>Make a bet</button>}
)
}
Log in modal in my App.js
const App = () => {
...
<Nav.Link className=' nav-item link-nav button-nav' onClick={handleShow}>
<img className='img-small' src={person} />
Log in
</Nav.Link>
<LoginForm show={show} handleShow={handleShow} handleClose={handleClose} />
}
I have everything as a separate component
I don't think it is possible. I think you can use Redux or Context to store the modal's open state.
I'm using image search and display app. Users can click on a photo and a modal would pop up. Those modal would have id in the url. However when I refresh the page, the modal isn't there and an error is shown. I get the url from unsplash api so with page refresh reload the url is gone. How do I Keep the url in url query so that the url persists even on page refresh?
Lisitem
import React, { useState } from "react";
import { Link, BrowserRouter as Router, Route } from "react-router-dom";
import ModalWrapper from "./ModalWrapper";
const ListItem = ({ photo }) => {
return (
<>
<Router>
<div key={photo.id} className="grid__item card">
<div className="card__body">
<Link to={{ pathname: `/${photo.id}`, state: photo }}>
<img src={photo.urls.small} alt="" />
</Link>
<Route path="/:photoId" component={ModalWrapper} />
</div>
</div>
</Router>
</>
);
};
export default ListItem;
Modal wrapper
import React from "react";
import Modal from "react-modal";
import { useHistory, useLocation } from "react-router-dom";
const customStyles = {
content: {
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
marginRight: "-50%",
transform: "translate(-50%, -50%)"
}
};
Modal.setAppElement("#root");
function ModalWrapper() {
const history = useHistory();
const location = useLocation();
const photo = location.state;
function downloadImage() {}
function close() {
history.push("/");
}
return (
<Modal isOpen={true} onRequestClose={close} style={customStyles}>
<img src={photo.urls.small} alt="" />
<div>
<button onClick={close} className="button">
Close
</button>
<button onClick={downloadImage()}>Download</button>
</div>
</Modal>
);
}
export default ModalWrapper;
The reason why it doesn't work when you refresh the page is because the photo that you passed as a param while navigating is no longer available. But, pathname is something that's still available (because it's part of the URL itself)
So, on the ModalWrapper page, you can check if photo is absent, then make a new API call to get the photo based on the id that is available in the pathname. I've never used unsplash API but I think it would be this API.
Your ModalWrapper would look like this
function ModalWrapper() {
const history = useHistory();
const location = useLocation();
const [photo, setPhoto] = useState(location.state);
useEffect(() => {
if (location.pathname && !location.state) {
// call the new API here using pathname (photo ID) and setPhoto
console.log(location.pathname);
}
}, [location]);
function downloadImage() {}
function close() {
history.push("/");
}
return (
!!photo && (
<Modal isOpen={true} onRequestClose={close} style={customStyles}>
<img src={photo.urls.small} alt="" />
<div>
<button onClick={close} className="button">
Close
</button>
<button onClick={downloadImage()}>Download</button>
</div>
</Modal>
)
);
}
You haven't asked this but, I would also move the Router and Route outside the ListItem and keep it in App.js (wrapping everything in there with Router). Keeping it in ListItem is like having a router and route for each list-item, which is not something you would ideally want. You would want to keep one router and route across the application, and it usually belongs to App.js or a wrapper or sorts. Here's the codesandbox after such changes
I have been searching SO for a while so this should not be a duplicate. But, I am trying to trigger a link click when the enter key is pressed.
This is what I am working with:
handleKeyPress(target) {
if(target.charCode==13){
alert('Enter clicked!!!');
}
}
Search input:
<SearchBox
type="text"
value={value}
onChange={e => this.onChange(e)}
className="search-box"
placeholder="Search"
aria-label="search"
aria-describedby="basic-addon2"
onKeyPress={this.handleKeyPress}
/>
<div>
<Link to={`/search?q=${value}`} className="btn submit-button"><i className="fa fa-search"></i></Link>
</div>
Using React Instant Search I want to submit the inputs 'value' when enter is clicked. Currently I can only submit the value when I physically click on:
<div>
<Link to={`/search?q=${value}`} className="btn submit-button"><i className="fa fa-search"></i></Link>
</div>
I can get the link to fire. But, how can I get the same functionality as the link click when I press enter too? Any suggestions on how to link to the search value via KeyPress?
If you already react-router-dom you can use the following:
import { withRouter } from 'react-router-dom'
class *ClassName* extends React.Component {
..
handleKeyPress(target, value) {
const { history } = this.props;
if(target.charCode==13){
history.push(`/search?q=${value}`);
}
}
..
render() {
return (
..
<SearchBox
value={value}
..
onKeyPress={e => this.handleKeyPress(e, value)}
/>
)
}
..
}
export default withRouter(*ClassName*);
Important here ist that you use the withRouter(..) export to get the history from your props.
According to react-statics documentation they recommend installing Reach Router for dynamic routing. To navigate programmatically with Reach Router you should be able to import navigate.
import { navigate } from "#reach/router"
...
handleKeyPress(target) {
// I'm guessing you have value stored in state
const { value } = this.state;
if(target.charCode==13){
navigate(`/search?q=${value}`);
}
}
Option 2
Honestly that seems like a lot of work when you could probably just do it with javascript.
handleKeyPress(target) {
// I'm guessing you have value stored in state
const { value } = this.state;
if(target.charCode==13){
const { href } = window.location;
window.location.href = `${href}/search?q=${value}`;
}
}
I am working on implementing "invite someone" functionality on a webapp. I have a "invite" button. Now I want that whenever someone clicks on it, a popup should apear on screen asking for an email id as input, which I can use to send an invite link. So I am not sure how to have that popup with an input field.
Apologies if someone find this question too basic. I am pretty new to react.js
You can handle the open and close state of your popup with the component state. You can either use css or Javascript to show or hide the popup.
If you use CSS you need to pass a css class to the popup like so:
class App extends Component {
state = {
open: false
}
handlePopUp(){
this.setState({open: !this.state.open})
}
render() {
return (
<div className="App">
<button onClick={() => this.handlePopUp()}>Open / close</button>
<div className={`modal ${this.state.oepn}`}>
{/* form content here */}
</div>
</div>
);
}
}
If you are using Javascript you will need to have a conditional like so:
class App extends Component {
state = {
open: false
}
handlePopUp(){
this.setState({open: !this.state.open})
}
render() {
return (
<div className="App">
<button onClick={() => this.handlePopUp()}>Open / close</button>
{
this.state.oepn ?
<div className="modal">
{/* form content here */}
</div>
: null
}
</div>
);
}
}
export default App;
I would recommend handling it with CSS so you can do some nice css transitions