Navbar not updating after state change - javascript

As the title says my navbar is not changing the fragments after updating the state. I have no idea how to refresh it and other ideas seems to not work for me. I have tried to change the statements.
All i want to do is, after a user logs in successfully the state changes to true and the navbar updates with the corrent components. Thank you !
Home.js
import React, { useEffect } from 'react'
function Home() {
useEffect(()=>{
if(!localStorage.getItem("loggedIn")){
localStorage.setItem("loggedIn",false);
}
},[]);
return (
<div>
Home
</div>
)
}
export default Home
Login.js
import React from 'react';
import './Login.css';
import Axios from 'axios';
import { useEffect, useState } from "react";
import {useHistory} from 'react-router-dom';
function Login() {
const[username,setUsername] = useState('');
const[password,setPassword] = useState('');
const[errorMessage,setErrorMessage] = useState('');
let history = useHistory();
const login = () =>{
console.log(username);
Axios.post("http://localhost:3001/user/login",{username: username,password: password}).then((response) => {
//console.log(response);
if(response.data.loggedIn){
localStorage.setItem("loggedIn",true);
localStorage.setItem("username",response.data.username);
history.push('/');
}else{
setErrorMessage(response.data.message);
}
});
};
return (
<div className="Login">
<h1>Login to your BugTrack account !</h1>
<div className="LoginForm">
<input type="text" placeholder="USERNAME"
onChange={(event)=>{setUsername(event.target.value)}}/>
<input type="password" placeholder="PASSWORD"
onChange={(event)=>{setPassword(event.target.value)}}/>
<button onClick={login}>Login to you account</button>
<h1 style={{color: "red"}}>{errorMessage}</h1>
</div>
</div>
);
}
export default Login
Navbar.js
import React, { useEffect, useState, Component, Fragment } from 'react';
import './Navbar.css';
function Navbar() {
const [loggedIn, setLoggedIn] = useState(false);
useEffect(()=> {
setLoggedIn(localStorage.getItem("loggedIn"));
},[localStorage.getItem("loggedIn")]);
return (
<div className="Navbar">
Home
{!loggedIn ? (
<Fragment>
Profile
</Fragment>
):(
<Fragment>
Register
Login
</Fragment>
)}
</div>
);
}
export default Navbar;

You want to to use localStorage as a useEffect dependency which isn't supports for React to rerender/update the component. Check this: useEffect do not listen for localStorage - it's like duplicate of your question.

Related

Is there a way I can solve the module not found error in javascript?

I am creating a todo list web app but some and this error is occurring where it says
Compiled with problems:
ERROR in ./src/Components/TodoList.js 6:0-57
Module not found: Error: Can't resolve './react/cjs/react.development' in 'C:\Users\91826\Desktop\WD\projects\todo-list\src\Components'
Can someone please tell me how to solve this.
Code in TodoForm.js
import React, {useState} from "react";
export default function TodoForm(props){
// state
const [input, setInput] = useState("");
const handleChange = e => {
setInput(e.target.value)
}
const handleSubmit = (e) => {
e.preventDefault();
props.addTask({
id: Math.floor(Math.random() * 1000000),
text: input,
isComplete: false
})
setInput('')
}
return(
<form>
<input type="text" placeholder="Add a todo" onChange={handleChange} className="todo-input" value={input} name="text"/>
<button type="submit" onClick={handleSubmit} className= "todo-btn" >ADD TODO</button>
</form>
);
}
Code in TodoList.js
import React from 'react';
import {useState} from '.react/cjs/react.development';
import TodoForm from './TodoForm'
export default function TodoList(){
const [todos, setTodos] = useState([]);
const addTask = task => {
if (!task.text) {
return
}
const newTodos = [task, ...todos];
setTodos(newTodos);
}
return <div>
<TodoForm addTask={addTask} ></TodoForm>
</div>;
}
Code in App.js
import './App.css';
import TodoList from './Components/TodoList'
function App() {
return (
<div className="Todo-list-container">
<TodoList/>
</div>
);
}
export default App;
useState should be imported from React itself, so these 2 lines:
import React from 'react';
import {useState} from './react/cjs/react.development';
Should be changed to
import React, { useState } from "react";

how pass function between sibilngs components in reactjs

so i have 2 component are sibiling one call and
and i went to pass a function from NavBar component to Login component
i try to do that becouse i went when the user login i can call to function from the NavBar to update the state in the Navbar component
i add here the code of 2 components
this the NavBar component and i went to pass the userLog function from her
import axios from "axios";
import React, { useEffect, useState } from "react";
import { NavLink } from "react-router-dom";
import Cookies from 'js-cookie';
import Login from "../auth/login/Login";
import { useLocation } from 'react-router-dom';
import './navBar.css'
function NavBar() {
const [cookie, setCookie] = useState(null)
const userLog = () => {
if (localStorage.getItem("login")) {
setCookie(true)
}
}
const logout = async () => {
console.log("logout")
const res = await axios.get('http://127.0.0.1:3000/users/logout', { withCredentials: true })
.then(res => {
if (res.data.status == "success") {
console.log('sss')
setCookie(false)
localStorage.setItem('login', 'false')
}
})
}
return (
<div className="nav-bar-container">
<img className="imgLogo" src="data:image/png;base64,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" />
<ul className="main-nav">
<li><NavLink className="navLink" to="/">Home</NavLink></li>
<li><NavLink className="navLink" to="/">Contact</NavLink></li>
<li><NavLink className="navLink" to="/login">Login</NavLink></li>
{/* {cookie === true ? <li><NavLink className="navLink" to="/">username</NavLink></li> : <li><NavLink className="navLink" to="/login">Login</NavLink></li>} */}
<li><NavLink onClick={logout} className="navLink" to='/' >Logout</NavLink></li>
<li><NavLink className="navLink" to="/sign-in">Signin</NavLink></li>
{/* <button onClick={() => user()}>user</button> */}
{/* <button onClick={() => log()}>dddd</button> */}
</ul>
</div>
);
}
export default NavBar;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
this the Login component and i went to get the userLog function and call it in the login function that i call by onClick
import axios from "axios";
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useLocation } from 'react-router-dom';
import './Login.css'
function Login(props) {
const [email, setEmail] = useState("")
const [password, setPass] = useState("")
const [cookie, setCookie] = useState(Boolean)
let navigate = useNavigate();
const location = useLocation()
const login = async (props) => {
console.log(email, password);
try {
const res = await axios.create({ withCredentials: true }).post(`http://127.0.0.1:3000/users/login`, {
email: email,
password: password
});
if (!res) {
return "not work"
}
console.log(res.data.data.user)
localStorage.setItem('login', 'true')
navigate("/", { replace: true });
} catch (error) {
console.log(error);
}
};
return (
<div className="pop-container">
<div className="popup">
<div className="content">
<h1>Sign in</h1>
<div className="input-field"><input placeholder="Email" className="validate" onChange={(e) => setEmail(e.target.value)} /></div>
<div className="input-field"><input placeholder="Password" className="validate" onChange={(e) => setPass(e.target.value)} /></div>
<button onClick={(e) => login(e)} className="second-button">Sign in</button>
<p>Don't have an account? Sign Up</p>
</div>
</div>
</div>
);
}
export default Login;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I try to use useLocation and also pass state in NavLink in the NavLink component
but thay cant get a function
to pass some date like string i success its not a problem but function I not success
There isn't a direct way to pass between sibling components. One option is to pass from sibling 1 -> parent component -> sibling 2. So with your "NavBar" and "Login" components you can lift state up from Navbar to the App (parent) component and then down to the Login component.
Option 2 would be setting up something like a useContext hook. Context is for setting global state variables to avoid unnecessary prop drilling.

How to pass data by button click in redux react js

I'm new to redux. I have three components are TextField , Button and View. I just stored textfield data in redux configureStore, How to pass data by button click from button component to view component. Im using context how to change in redux.
Codesandbox link using redux
Here I tired but I want to diplay only when button click.
CodeSanbox Link using Context
Here is the solution I make ready for you
App.js
import "./styles.css";
import Tfield from "./Tfield";
import ButtonSubmit from "./ButtonSubmit";
import TypoValue from "./TyoValue";
import React, { useCallback, useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { updateValue } from "./features/user";
export default function App() {
const dataFromRedux = useSelector((state) => state.user.value);
console.log(dataFromRedux);
// useRef to prevent re-rendering
const inputRef = React.useRef(undefined);
const dispatch = useDispatch();
const handleUpdate = () => {
dispatch(updateValue(inputRef.current.value));
};
return (
<div className="App">
<Tfield inputRef={inputRef} />
<ButtonSubmit handleUpdate={handleUpdate} />
<TypoValue />
</div>
);
}
Tfield.js
import "./styles.css";
import * as React from "react";
import TextField from "#mui/material/TextField";
export default function Tfield({ inputRef }) {
console.log("Textfield");
return (
<div>
<TextField
inputRef={inputRef}
label="Enter Name"
/>
</div>
);
}
BtnPage.js
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { updateValue } from "./features/Updater";
export default function BtnPage({handleUpdate}) {
return (
<div>
<button onClick={() => handleUpdate()}> Update </button>
</div>
);
}
TFPage.js
import React, { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { updateValue } from "./features/Updater";
export default function TFPage({myTxt, setMyTxt}) {
//const myData = useSelector((state) => state.update.value);
// const [myTxt, setMyTxt] = useState(myData.text);
//const dispatch = useDispatch();
const handleChange = (char) => {
setMyTxt(char);
//dispatch(updateValue(myTxt));
};
// useEffect(() => {
// // console.log('useEff - render');
// dispatch(updateValue({ text: myTxt }));
// }, [myTxt]);
return (
<div>
<input
value={myTxt}
placeholder="Enter Some Text"
onChange={(e) => handleChange(e.target.value)}
/>
</div>
);
}
ViewPage.js
import React from "react";
import { useSelector } from "react-redux";
export default function ViewPage() {
const myData = useSelector((state) => state.update.value);
console.log(myData);
return (
<div>
<h1> {myData} </h1>
</div>
);
}
As per your Codesandbox link using redux Code.
I think you have to change from import updateValue from "./features/Updater"; to import { updateValue } from "./features/Updater";
And it works fine for me
Your current App.js file
import "./styles.css";
import TFPage from "./TFPage";
import BtnPage from "./BtnPage";
import ViewPage from "./ViewPage";
import { useSelector, useDispatch } from "react-redux";
import updateValue from "./features/Updater";
import { useState, React } from "react";
export default function App() {
const myData = useSelector((state) => state.update.value);
const [myTxt, setMyTxt] = useState(myData.text);
const dispatch = useDispatch();
const handleUpdate = () => {
console.log(myData);
dispatch(updateValue(myTxt));
};
return (
<div className="App">
<TFPage setMyTxt={setMyTxt} myTxt={myTxt} />
<BtnPage handleUpdate={handleUpdate} />
<ViewPage />
</div>
);
}
Your App.js file should look like below
import "./styles.css";
import TFPage from "./TFPage";
import BtnPage from "./BtnPage";
import ViewPage from "./ViewPage";
import { useSelector, useDispatch } from "react-redux";
import { updateValue } from "./features/Updater";
import { useState, React } from "react";
export default function App() {
const myData = useSelector((state) => state.update.value);
const [myTxt, setMyTxt] = useState(myData.text);
const dispatch = useDispatch();
const handleUpdate = () => {
console.log(myData);
console.log(myTxt);
dispatch(updateValue(myTxt));
};
return (
<div className="App">
<TFPage setMyTxt={setMyTxt} myTxt={myTxt} />
<BtnPage handleUpdate={handleUpdate} />
<ViewPage />
</div>
);
}
You can also get a better understanding of the redux toolkit from this given doc Redux toolkit explaination for a better understanding
Your reducer has the following structure:
initialState: { value: { text: "" } }
But you are triggering an action like this:
dispatch(updateValue("youy text here"));
When it should be like this:
dispatch(updateValue({ text: "your text here" }));

Object is undefined when trying to fetch it using useContext()

I am very new to React and was trying to make a context in React so that in my notes app such that I can trigger my custom made alert for relevant user activity but when I am trying to use the values from the context using useContext I am getting error : "Cannot destructure property 'alert' of 'Object(...)(...)' as it is undefined."
Here's the code:-
Creating Context
import React from 'react';
const AlertContext = React.createContext(null);
export default AlertContext;
Populating Value to the Context
import React,{useState} from 'react';
import AlertContext from "./AlertContext";
const ShowAlert = (props)=>{
const [alert,setAlert] = useState(null);
const showAlert = (message,type)=>{
setAlert({
msg:message,
type:type
})
setTimeout(()=>{
setAlert(null);
},3000);
}
return(
<AlertContext.Provider value={{alert,showAlert}}>
{props.children}
</AlertContext.Provider>
)
}
export default ShowAlert;
Trying to use the values
import React, { useContext } from "react";
import { Navbar, Button, Nav } from "react-bootstrap";
import { Link, useHistory } from "react-router-dom";
import ShowAlert from "../contexts/ShowAlert";
import MyAlert from "./MyAlert";
function Header() {
const {alert} = useContext(ShowAlert);
let history = useHistory();
const handleLogout = () => {
localStorage.removeItem("token");
history.push("/login");
};
return (
<>
<header>
<Navbar collapseOnSelect expand="lg" className="header">
<Navbar.Brand className="heading">
<Link to="/" className="headerLink">
Note Cloud
</Link>
<i className="fas fa-cloud-upload-alt cloudIcon"></i>
</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="me-auto"></Nav>
{localStorage.getItem("token") && (
<Nav>
<Nav.Link>
<Button variant="primary" size="lg" onClick={handleLogout}>
Logout
</Button>
</Nav.Link>
</Nav>
)}
</Navbar.Collapse>
</Navbar>
</header>
<MyAlert alert={alert}></MyAlert>
</>
);
}
export default Header;
Edit:- MyAlert Component
import React, { useContext } from "react";
import { Alert } from "react-bootstrap";
import ShowAlert from "../contexts/ShowAlert";
const MyAlert = (props) => {
const {alert} = useContext(ShowAlert);
const capitalize = (word) => {
if(word==="danger")
{
word = "error";
}
const lower = word.toLowerCase();
return lower.charAt(0).toUpperCase() + lower.slice(1);
};
return (
<div style={{ height: "50px" , width:"100%"}}>
{alert && (
<Alert
variant={alert.type}
>
<Alert.Heading>{capitalize(alert.type)}</Alert.Heading>
<p>{capitalize(alert.msg)}</p>
</Alert>
)}
</div>
);
};
export default MyAlert;
Error That I am getting
Try doing the Context like this instead of null.
import React from "react";
const AlertContext = React.createContext({
alert: {},
setAlert: (alert) => {},
});
export default
i think your export is the fail
export const AlertContext = React.createContext({})
or as well you can try:
< AlertContext.Consumer>
{(context) => {
console.log(context)
}}
</AlertContext.Consumer>

React hooks and context api localstorage on refresh

In my SPA, I am utilizing react hooks and context API. I need to persist the current state of the component view rendered using the context API so that I can implement the global component conditional rendering through the application.
I have two views on a single dashboard page: overview & detail. The button triggers the global state change and the view should be fixed on the state value even on page refresh.
Here's my code snippets:
AppRoutes file
import React, { useState } from "react";
import { Router, Route, Switch } from "react-router-dom";
import history from "../utils/history";
import { PyramidProvider } from "../context/pyramidContext";
import Dashboard from "../pages/dashboard/Dashboard";
const AppRoutes = () => {
return (
<div>
<React.Suspense fallback={<span>Loading...</span>}>
<Router history={history}>
<Switch>
<PyramidProvider>
<Route path="/" component={Dashboard} />
</PyramidProvider>
</Switch>
</Router>
</React.Suspense>
</div>
);
};
export default AppRoutes;
Dashboard page
import React, { useState, useEffect, useContext } from "react";
import { PyramidContext } from "../../context/pyramidContext";
import PyramidDetail from "../../components/pyramidUI/pyramidDetail";
import PyramidOverview from "../../components/pyramidUI/pyramidOverview";
const Dashboard = (props) => {
const { info, setInfo } = useContext(PyramidContext);
return (
<React.Fragment>
{info.uiname === "overview" ? <PyramidOverview /> : <PyramidDetail />}
</React.Fragment>
);
};
export default Dashboard;
Overview component
import React, { useState, useContext } from "react";
import { PyramidContext } from "../../context/pyramidContext";
const Overview = (props) => {
const { info, setInfo } = useContext(PyramidContext);
return (
<div className="d-flex flex-column dashboard_wrap">
<main>
<div className="d-flex">
<button
onClick={() => setInfo({ uiname: "detail", pyramidvalue: 1 })}
>
change view
</button>
</div>
</main>
</div>
);
};
export default Overview;
Detail component
import React, { useContext } from "react";
import { PyramidContext } from "../../context/pyramidContext";
// import axios from "axios";
const Detail = (props) => {
const { info, setInfo } = useContext(PyramidContext);
return (
<div className="d-flex flex-column dashboard_wrap">
<h2>Detail View</h2>
<div>
<button
type="button"
onClick={() => setInfo({ uiname: "overview", pyramidvalue: 0 })}
>
Back
</button>
</div>
</div>
);
};
export default Detail;
Context File
import React, { createContext, useEffect, useReducer } from "react";
let reducer = (info, newInfo) => {
return { ...info, ...newInfo };
};
const initialState = {
uiname: "overview",
pyramidvalue: 0,
};
const localState = JSON.parse(localStorage.getItem("pyramidcontent"));
const PyramidContext = createContext();
function PyramidProvider(props) {
const [info, setInfo] = useReducer(reducer, initialState || localState);
useEffect(() => {
localStorage.setItem("pyramidcontent", JSON.stringify(info));
}, [info]);
return (
<PyramidContext.Provider
value={{
info,
setInfo,
}}
>
{props.children}
</PyramidContext.Provider>
);
}
export { PyramidContext, PyramidProvider };
I click the button to render a detail view and soon as the page is refreshed, the component changes its view to overview instead of sticking around to detail. I checked the local storage values, and it is being updated properly, but still, the component view does not persist as per the value.
I am unable to understand where I am doing wrong, any help to resolve this issue, please? Thanks in advance.
You're never using the value of localStage in your info state,
you should replace your code with:
const [info, setInfo] = useReducer(reducer, localState || initialState);

Categories

Resources