Context doesn't update in React.js. how to implement a solution? - reactjs

in react i have tried to implement a solution to forward values with context.
but my context doesn't work in another page(component)
this is my MainPage where user logins in login part
what i want is ;
i want to check login here and if login res != null then i want to set these res data into context values and use them in the bookPage
import React from "react";
import{ useContext, useEffect, useState } from "react";
import { TextField } from "#mui/material";
import { Button } from "#mui/material";
import "./Pages.css";
import { AccountContext } from "./AccountProvider";
import { useHistory } from "react-router-dom";
import axios from "axios";
function MainPage() {
const [email, setEmail1] = useState("");
const [password, setPassword1] = useState("");
const [name, setName1] = useState("");
const [loginemail, setloginEmail] = useState("");
const [loginpassword, setloginPassword] = useState("");
const [registeremail, setregisterEmail] = useState("");
const [registerpassword, setregisterPassword] = useState("");
const [registername, setregisterName] = useState("");
const {
Name,
Mail,
Password,
UID,
setName,
setPassword,
setMail,
setUID,
} = useContext(AccountContext);
let history = useHistory();
const [data,setData] = useState([]);
const LoginClick = () => {
setEmail1(loginemail);
setPassword1(loginpassword);
axios
.get( `http://localhost:5000/getLogin/?email=${email}&password=${password}`)
.then((resp) => {
setUID(resp.data[0]._id)
setName(resp.data[0].name)
setMail(resp.data[0].email)
setPassword(resp.data[0].password)
console.log(UID)
if (resp.data[0]._id != null) {
history.push("/BookPage")
history.go()
}
})
.catch((e) => {
alert(e);
});
};
const RegisterClick = async (e) => {
setEmail1(registeremail);
setName1(registername);
setPassword1(registerpassword);
console.log(email, password)
let res = await fetch("http://localhost:5000/registerUser", {
method: "post",
body: JSON.stringify({ name, email, password }),
headers: {
"Content-Type": "application/json",
},
});
res = await res.json();
console.warn(res);
if (res) {
alert("Registered success");
setName1("");
setPassword1("");
setEmail1("");
history.push("/BookPage");
}
if (!res) {
alert("registered failed");
}
};
return (
<>
<div class="main-page">
<h1>Welcome to the Library Management System!!! </h1>
<div class="user-form">
<div class="login-form">
<h2>User Login </h2>
<TextField
id="loginemail"
label="email"
variant="filled"
type="email"
value={loginemail}
onChange={(e) => {setloginEmail(e.target.value)
setEmail1(e.target.value)
setMail(e.target.value)
}}
/>
<TextField
id="loginpassword"
label="password"
variant="filled"
type="password"
value={loginpassword}
onChange={(e) => {setloginPassword(e.target.value)
setPassword1(e.target.value)
setPassword(e.target.value)
}}
/>
<Button variant="outlined" onClick={LoginClick
}>
{" "}
Login
</Button>
</div>
<div class="register-form">
<h2>New User? Register Here!</h2>
<TextField
id="registername"
label="name"
variant="filled"
value={registername}
onChange={(e) => {setregisterName(e.target.value)
setName1(e.target.value)}}
/>
<TextField
id="regsiteremail"
label="email"
variant="filled"
type="email"
value={registeremail}
onChange={(e) => {setregisterEmail(e.target.value)
setEmail1(e.target.value)
}}
/>
<TextField
id="registerpassword"
label="password"
variant="filled"
value={registerpassword}
onChange={(e) => {setregisterPassword(e.target.value)
setPassword1(e.target.value)
}}
/>
<Button variant="outlined" onClick={RegisterClick}>
{" "}
Register
</Button>
</div>
</div>
</div>
</>
);
}
export default MainPage;
this is my bookPage and here i want to use my user data
even on title (h1) it doesn't shown in there
i tried to console.log but it doesn't worked either
somehow these values doesn't change or update
import React from "react";
import { AccountContext } from "./AccountProvider";
export default function BookPage() {
const { Id, Name, Email, Password, setID, setName, setEmail, setPassword } =
useContext(AccountContext); //this is where i expect to get values from mainPage
return (
<>
<div className="book-page">
<h1>
Welcome , {Id} {Email} {Name}
</h1>
</>
)
}
this is the context i try to use
import { createContext, useState } from "react";
import React from "react";
const AccountContext = createContext();
function AccountProvider(props) {
const [Mail, setMail] = useState("");
const [Password, setPassword] = useState("");
const [UID, setUID] = useState("");
const [Name,setName] = useState("");
return (
<AccountContext.Provider
value={{
Mail: Mail,
Password: Password,
UID: UID,
Name:Name,
setMail,
setPassword,
setUID,
setName,
}}
>
{props.children}
</AccountContext.Provider>
);
}
export {AccountContext, AccountProvider};
and this is the index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { AccountProvider } from "./PAGES/AccountProvider";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<AccountProvider>
<App />
</AccountProvider>
</React.StrictMode>
);
i have tried many solutions but i couldn't found any of them work
edit(1)
this is my routerPage
import React from "react";
import MainPage from "./MainPage";
import Deneme from "./deneme";
import { Router, Switch, Route } from "react-router-dom";
import BookPage from "./BookPage";
import { createBrowserHistory } from "history";
export default function RouterPage() {
let history= createBrowserHistory();
return (
<div>
<Router history={history}>
<Switch>
<Route exact path="/">
<MainPage />
</Route>
<Route exact path="/BookPage">
<BookPage />
</Route>
<Route path="/deneme">
<Deneme />
</Route>
</Switch>
</Router>
</div>
);
}
and in the app component
import React from 'react';
import RouterPage from "./PAGES/RouterPage.js";
function App() {
return (
<RouterPage/>
);
}
export default App;

Related

In react Firebase Chat App i have afirst issue with closed Socket and a second with redirection after signin with google

My 4 js files are the following.i use react router v6 and after the signin in useEffect tried to redirect in chats page.
import "./App.css";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Login from "./components/Login";
import Chats from "./components/Chats";
import { AuthProvider } from "./contexts/AuthContext";
function App() {
return (
<div style={{ fontFamily: "Avenir" }}>
<Router>
<AuthProvider>
<Routes>
<Route path="/" element={<Login />} />
<Route path="/chats" element={<Chats />} />
</Routes>
</AuthProvider>
</Router>
</div>
);
}
export default App;
import React from "react";
import { useNavigate } from "react-router-dom";
import { Col, Row } from "react-grid-system";
import {
ChatEngineWrapper,
Socket,
ChatList,
ChatFeed,
ChatSettings,
} from "react-chat-engine";
import { auth } from "../firebase";
import { useAuth } from "../contexts/AuthContext";
const Chats = () => {
const navigate = useNavigate();
const { user } = useAuth();
console.log(user);
const handleLogout = async () => {
await auth.signOut();
navigate("/", { replace: true });
};
return (
<div className="chats-page">
<div className="nav-bar">
<div className="logo-tab">TotalChat</div>
<div onClick={handleLogout} className="logout-tab">
Logout
</div>
</div>
<ChatEngineWrapper height="calc(100vh - 66px)">
<Socket
projectID={process.env.REACT_APP_PROJECT_ID}
userName={process.env.REACT_APP_USERNAME}
userSecret={process.env.REACT_APP_USER_SECRET}
/>
<Row>
<Col xs={0} sm={3}>
<ChatList />
</Col>
<Col xs={12} sm={6}>
<ChatFeed />
</Col>
<Col xs={0} sm={3}>
<ChatSettings />
</Col>
</Row>
</ChatEngineWrapper>
</div>
);
};
export default Chats;
import React from "react";
import { GoogleOutlined, FacebookOutlined } from "#ant-design/icons";
import { auth } from "../firebase";
import firebase from "firebase/compat/app";
const Login = () => {
return (
<div id="login-page">
<div id="login-card">
<h2>Welcome To Total Chat!</h2>
<div
className="login-button google"
onClick={() =>
auth.signInWithRedirect(new firebase.auth.GoogleAuthProvider())
}
>
<GoogleOutlined /> Sign In with Google
</div>
<br />
<br />
<div
className="login-button facebook"
onClick={() =>
auth.signInWithRedirect(new firebase.auth.FacebookAuthProvider())
}
>
<FacebookOutlined /> Sign In with Facebook
</div>
</div>
</div>
);
};
export default Login;
import React, { useContext, useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { auth } from "../firebase";
// import io from "socket.io-client";
// let socket = io.connect("wss://localhost:3000");
const AuthContext = React.createContext();
export const useAuth = () => useContext(AuthContext);
export const AuthProvider = ({ children }) => {
const [loading, setLoading] = useState(true);
const [user, setUser] = useState("");
const navigate = useNavigate();
useEffect(() => {
auth.onAuthStateChanged((user) => {
// socket.on();
setUser(user);
setLoading(false);
if (user) navigate("/chats");
});
}, [user, navigate]);
const value = { user };
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
);
};
Errors
closed socket
I am completely new to this and i do not know if the redirection problem also caused by socket or connection issues.If anybody has an idea about it i would be grateful.Thanks in advance!

How to pass functions and variables from Context API Provider to another components?

I need to restrict links in react router by specific user roles (I have roles stored in token). What I'm trying to do now is:
send username & password through SignIn component to getTokens() function from custom useAuth hook on submit to then pass a boolean isModerator inside route value to ensure that the user have the required authorities for the link to show. In my case request is just not going to the server on form submit, probably because I misuse context api or react itself somehow.
So this is how my useAuth hook looks right now:
import React, { useState, createContext, useContext, useEffect } from "react";
import axios from "axios";
export const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const [authed, setAuthed] = useState(false);
const [moderator, setModerator] = useState(false);
const [accessToken, setAccessToken] = useState("");
const [refreshToken, setRefreshToken] = useState("");
const [authorities, setAuthorities] = useState([]);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const signIn = async (e, username, password) => {
e.preventDefault();
const result = await getTokens(username, password);
if (result) {
console.log("User has signed in");
setAuthed(true);
}
};
const isModerator = async () => {
const result = await getAccessTokenAuthorities();
if (result) {
console.log("User is admin");
setModerator(true);
}
};
const getTokens = async (username, password) => {
const api = `http://localhost:8080/api/v1/public/signIn?username=${username}&password=${password}`;
const res = await axios.get(api, {
withCredentials: true,
params: {
username: username,
password: password,
},
});
const data = await res.data;
setAccessToken(data["access_token"]);
setRefreshToken(data["refresh_token"]);
console.log(data);
return accessToken, refreshToken;
};
const getAccessTokenAuthorities = async () => {
const api = `http://localhost:8080/api/v1/public/getAccessTokenAuthorities`;
const res = await axios.get(api, {
withCredentials: true,
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
const data = await res.data;
setAuthorities(data);
let vals = [];
authorities.forEach((authority) => {
vals.push(Object.values(authority));
});
const check = vals.filter((val) => val.toString() === "MODERATOR");
if (check.length > 0) return !isModerator;
console.log(authorities);
return isModerator;
};
return (
<AuthContext.Provider
value={{
authed,
setAuthed,
moderator,
setModerator,
getTokens,
getAccessTokenAuthorities,
username,
password,
setUsername,
setPassword,
}}
>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
And this is me trying to use AuthContext in SignIn component:
import React, { useContext, useEffect, useState } from "react";
import { useAuth } from "../hooks/useAuth";
import { AuthContext } from "../hooks/useAuth";
const SignIn = (props) => {
const auth = useAuth();
const userDetails = useContext(AuthContext);
return (
<>
<h1>Вход</h1>
<form
method="get"
onSubmit={(e) => auth.signIn(e)}
encType="application/json"
>
<label htmlFor="username">Имя пользователя</label>
<input
type="text"
id="username"
onChange={(e) => userDetails.setUsername(e.target.value)}
></input>
<label htmlFor="password">Пароль</label>
<input
type="password"
id="password"
onChange={(e) => userDetails.setPassword(e.target.value)}
></input>
Вход
<input type="submit"></input>
</form>
</>
);
};
SignIn.propTypes = {};
export default SignIn;
Here is how I set my AuthProvider in index.js:
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css"; import reportWebVitals from "./reportWebVitals";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Inventory from "./components/Inventory";
import SignIn from "./components/SignIn";
import { AuthProvider } from "./hooks/useAuth";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/"
element={<App />}>
</Route>
<Route path="api/v1/public/signIn"
element={<SignIn />}>
</Route>
<Route path="api/v1/moderator/inventory" element={<Inventory />} >
</Route>
</Routes>
</AuthProvider>
</BrowserRouter>
</React.StrictMode> );
reportWebVitals();
Thanks in advance.
You're creating 2 instances of context when you initialize 2 variables of it.
Both of these variables are behaving as separate instances of context. Its like when an object is initialized from a constructor.
All the methods you've passed to context Provider are available on const auth=useAuth(). Inside your Signin component, you're calling userDetails.setUsername() for changing value of username and to submit the form you're calling auth.signin.
You can simply use auth.setUsername(e.target.value) and auth.setPassword(e.target.value). For submitting form use auth.signin()
const SignIn = (props) => {
const auth = useAuth();
// const userDetails = useContext(AuthContext); No need to initialize this one
useEffect(() => {
// here in this log you will see all the methods are available from context provider
if (auth) console.log(auth);
}, [auth]);
return (
<>
<h1>Вход</h1>
<form
method="get"
onSubmit={(e) => auth.signIn(e)}
encType="application/json"
>
<label htmlFor="username">Имя пользователя</label>
<input
type="text"
id="username"
onChange={(e) => auth.setUsername(e.target.value)}
></input>
<label htmlFor="password">Пароль</label>
<input
type="password"
id="password"
onChange={(e) => auth.setPassword(e.target.value)}
></input>
Вход
<input type="submit"></input>
</form>
</>
);
};
export default SignIn;

Navbar is not rendering in app.js based on routing condition. Useeffect is not getting triggered on route change

Here in this code, I'm using navbar based on condition if the user is logged in(if the user info is stored in localstorage), except login component, I'm rendering the navbar component.
But after successful login it in the respective component, at the first time routing, it is not showing navbar at top, it is showing only if I refresh the page.
I tried this solution, But this solution didnt work for me
components are below.
Thank You
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import 'bootstrap/dist/css/bootstrap.min.css';
import { BrowserRouter } from 'react-router-dom'
ReactDOM.render(
<React.StrictMode>
<BrowserRouter><App /></BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
App.js
import { React, useEffect,useState } from 'react'
import { BrowserRouter as Router, Switch, Route,withRouter } from 'react-router-dom'
import Login from './components/login/Login'
import Admin from './components/admin/Admin'
import ProtectedRoute from './ProtectedRoute'
import Navbar from './components/Navbar/Navbar'
const App = () => {
const [nb, setNb] = useState(false)
const checkIsAuth = () => {
const _isAuth = localStorage.getItem('isAuth');
const _user = localStorage.getItem('user');
const _password = localStorage.getItem('password');
if (_isAuth && _user && _password) setNb(true)
}
useEffect(() => {
checkIsAuth()
}, [])
return (
<div style={{ textAlign: "center" }}>
{nb && <Navbar />}
<Switch>
<ProtectedRoute exact path={`/admin`} component={Admin} />
<Route exact path="/" component={Login} />
</Switch>
</div>
);
}
export default withRouter(App);
Login.js
import { React, useEffect, useState } from 'react'
import { useHistory } from 'react-router-dom'
import { Form, Button } from 'react-bootstrap'
import { withRouter } from 'react-router-dom'
const Login = () => {
const history = useHistory()
const [userName, setUserName] = useState('')
const [password, setPassword] = useState('')
const submit = () => {
if ((userName === 'admin' || userName === 'operator' || userName === 'supervisor') && password === 'welcome') {
localStorage.setItem('user', userName)
localStorage.setItem('isAuth', true)
localStorage.setItem('password', password)
setPassword('');
setUserName('');
history.push(`/${userName}`)
}
else if (!((userName === 'admin' || userName === 'operator' || userName === 'supervisor') && password === 'welcome')) {
alert("Invalid Credentials")
setPassword('')
setUserName('')
history.push(`/`)
}
}
const checkIsAuth = () => {
const _isAuth = localStorage.getItem('isAuth');
const _user = localStorage.getItem('user');
const _password = localStorage.getItem('password');
if (_isAuth && _user && _password) history.push(`/${localStorage.getItem('user')}`)
}
useEffect(() => {
checkIsAuth()
}, [])
return (
<div>
<Form>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Username</Form.Label>
<Form.Control type="text" placeholder="Enter Username" onChange={e => setUserName(e.target.value)}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password" onChange={e => setPassword(e.target.value)} />
</Form.Group>
<Button variant="primary" onClick={submit}>
Submit
</Button>
</Form>
</div>
)
}
export default withRouter(Login)
ProtectedRoute.js
import React from 'react'
import { Route, Redirect } from 'react-router-dom'
const ProtectedRoute = ({ component: Component, ...rest }) => {
const checkIsAuth = () => {
const _isAuth = localStorage.getItem('isAuth');
const _user = localStorage.getItem('user');
const _password = localStorage.getItem('password');
let res = { isAuth: !!_isAuth, user: _user, password: _password }
return res
}
return (
<Route {...rest}
render={(props) => {
if (checkIsAuth().isAuth && checkIsAuth().user && checkIsAuth().password) {
return <Component />
}
else {
return <Redirect to={{ pathname: '/', state: { from: props.location } }} />
}
}}
/>
)
}
export default ProtectedRoute
Admin.js
import React from 'react'
import { withRouter } from 'react-router-dom'
const Admin = () => {
return (
<div>
Admin
</div>
)
}
export default withRouter(Admin)
Changes Required
App.js
import { React, useEffect,useState } from 'react'
import { BrowserRouter as Router, Switch, Route,withRouter } from 'react-router-dom'
import Login from './components/login/Login'
import Admin from './components/admin/Admin'
import ProtectedRoute from './ProtectedRoute'
import Navbar from './components/Navbar/Navbar'
const App = () => {
const [nb, setNb] = useState(false)
const checkIsAuth = () => {
const _isAuth = localStorage.getItem('isAuth');
const _user = localStorage.getItem('user');
const _password = localStorage.getItem('password');
if (_isAuth && _user && _password) setNb(true)
}
useEffect(() => {
checkIsAuth()
}, [])
return (
<div style={{ textAlign: "center" }}>
{nb && <Navbar />}
<Switch>
<ProtectedRoute exact path={`/admin`} component={Admin} />
<Route exact path="/" render={(routerProps) => <Login setNb={setNb}/>} />
</Switch>
</div>
);
}
export default withRouter(App);
Login.js
import { React, useEffect, useState } from 'react'
import { useHistory } from 'react-router-dom'
import { Form, Button } from 'react-bootstrap'
import { withRouter } from 'react-router-dom'
const Login = ({setNb}) => {
const history = useHistory()
const [userName, setUserName] = useState('')
const [password, setPassword] = useState('')
const submit = () => {
if ((userName === 'admin' || userName === 'operator' || userName === 'supervisor') && password === 'welcome') {
localStorage.setItem('user', userName)
localStorage.setItem('isAuth', true)
localStorage.setItem('password', password)
setPassword('');
setUserName('');
history.push(`/${userName}`);
setNb(true);
}
else if (!((userName === 'admin' || userName === 'operator' || userName === 'supervisor') && password === 'welcome')) {
alert("Invalid Credentials")
setPassword('')
setUserName('')
history.push(`/`)
}
}
const checkIsAuth = () => {
const _isAuth = localStorage.getItem('isAuth');
const _user = localStorage.getItem('user');
const _password = localStorage.getItem('password');
if (_isAuth && _user && _password) history.push(`/${localStorage.getItem('user')}`)
}
useEffect(() => {
checkIsAuth()
}, [])
return (
<div>
<Form>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Username</Form.Label>
<Form.Control type="text" placeholder="Enter Username" onChange={e => setUserName(e.target.value)}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password" onChange={e => setPassword(e.target.value)} />
</Form.Group>
<Button variant="primary" onClick={submit}>
Submit
</Button>
</Form>
</div>
)
}
export default withRouter(Login)

TypeError: Cannot read property 'pathname' of undefined

I am creating sign-up and sign-in on a website but I am getting this error TypeError: Cannot read property 'pathname' of undefined I have no idea where this error comes from. I am new to redux So if anyone knows why I get this error please explain to me, so the next time I will know if I still get this error.
Thank you
Here is my code
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import store from './Store';
window.store = store;
ReactDOM.render(
<Provider store= {store}>
<Router>
<React.StrictMode>
<App />
</React.StrictMode>
</Router>
</Provider>,
document.getElementById('root')
);
reportWebVitals();
app.js
import './App.css';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import HomePage from './Home_Search_Client/Containers/HomePage';
import About from './Home_Search_Client/Containers/About';
import Feedback from './Home_Search_Client/Containers/Feedback';
import Signup from './Home_Search_Client/Containers/Signup';
import Signin from './Home_Search_Client/Containers/Signin';
import PrivateRoute from './Home_Search_Client/Components/HOC/PrivateRoute';
import { useDispatch, useSelector } from 'react-redux';
import { useEffect } from 'react';
import { isUserLoggedIn } from './Home_Search_Client/actions';
function App() {
const dispatch = useDispatch();
const auth = useSelector((state) => state.auth);
useEffect(() => {
if(!auth.authenticate){
dispatch(isUserLoggedIn)
}
}, [auth.authenticate]);
return (
<Router>
<Switch>
<PrivateRoute path='/' exact component={HomePage} />
<PrivateRoute path='/about' component={About} />
<PrivateRoute path='/feedback' component={Feedback} />
<Route path='/signup' component={Signup} />
<Route path='/signin' component={Signin} />
</Switch>
</Router>
);
}
export default App;
Store (index.js)
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from '../Home_Search_Client/reducers';
import thunk from 'redux-thunk';
const store = createStore(rootReducer, composeWithDevTools(
applyMiddleware(thunk)
));
export default store;
auth.actinons.js
import axios from '../helpers/axios';
import { authConstants } from './constants';
export const signin = (user) => {
return async (dispatch) => {
dispatch({ type: authConstants.LOGIN_REQUEST });
const res = await axios.post(`/signin`, {
...user
});
if (res.status === 200) {
const { token, user } = res.data;
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
dispatch({
type: authConstants.LOGIN_SUCCESS,
payload: {
token, user
}
});
} else {
if (res.status === 400) {
dispatch({
type: authConstants.LOGIN_FAILURE,
payload: { error: res.data.error }
});
}
}
}
}
export const isUserLoggedIn = () => {
return async dispatch => {
const token = localStorage.getItem('token');
if (token) {
const user = JSON.parse(localStorage.getItem('user'));
dispatch({
type: authConstants.LOGIN_SUCCESS,
payload: {
token, user
}
});
}else{
dispatch({
type: authConstants.LOGIN_FAILURE,
payload: { error: 'Failed to login' }
});
}
}
}
export const signout = () => {
return async dispatch => {
dispatch({ type: authConstants.LOGOUT_REQUEST });
const res = await axios.post(`/signout`);
if (res.status === 200) {
localStorage.clear();
dispatch({ type: authConstants.LOGOUT_SUCCESS });
} else {
dispatch({
type: authConstants.LOGOUT_FAILURE,
payload: { error: res.data.error }
});
}
}
}
user.action.js
import axios from '../helpers/axios';
import { userContants } from './constants';
export const signup = (user) => {
return async (dispatch) => {
dispatch({ type: userContants.USER_REGISTER_REQUEST });
const res = await axios.post(`/signup`, {
...user
});
if (res.status === 201) {
const { message } = res.data;
dispatch({
type: userContants.USER_REGISTER_SUCCESS,
payload: { message }
});
} else {
if (res.status === 400) {
dispatch({
type: userContants.USER_REGISTER_FAILURE,
payload: { error: res.data.error }
});
}
}
}
};
Signup.js(Containers)
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Button, Col, Container, Form, Row } from 'react-bootstrap'
import Layout from '../../Components/Layout'
import Input from '../../Components/UI/Input'
import { signup } from '../../actions'
import { Redirect } from 'react-router'
const Signup = (props) => {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const auth = useSelector((state) => state.auth)
const user = useSelector((state) => state.user)
const dispatch = useDispatch();
useEffect(() => {
if(!user.loading){
setFirstName('');
setLastName('');
setEmail('');
setPassword('');
}
}, [user.loading]);
const userSignup = (e) => {
e.preventDefault();
const user = {
firstName,
lastName,
email,
password
};
dispatch(signup(user));
};
if(auth.authenticate) {
return <Redirect to={'/'} />
}
if(user.loading) {
return <p>Loading...</p>
}
return (
<Layout>
<Container>
{user.message}
<Row>
<Col md={{ span:6, offset:3 }}>
<Form onSubmit={userSignup}>
<Row>
<Col md = {6}>
<Input
label = 'First Name'
placeholder='First Name'
value= {firstName}
type='text'
onChange={(e) => setFirstName(e.target.value)}
/>
</Col>
<Col md = {6}>
<Input
label = 'Last Name'
placeholder='Last Name'
value= {lastName}
type='text'
onChange={(e) => setLastName(e.target.value)}
/>
</Col>
</Row>
<Input
label='Email'
placeholder='Email'
value={email}
type='email'
onChange={(e) => setEmail(e.target.value)}
/>
<Input
label='Password'
placeholder='Password'
value={password}
type='password'
onChange={(e) => setPassword(e.target.value)}
/>
<Button variant='primary' type='submit' >
Submit
</Button>
</Form>
</Col>
</Row>
</Container>
</Layout>
)
}
export default Signup
Signin.js(Containers)
import React, { useState } from 'react'
import { Button, Col, Container, Form, Row } from 'react-bootstrap'
import Layout from '../../Components/Layout';
import Input from '../../Components/UI/Input';
import { useDispatch, useSelector } from 'react-redux';
import { signin } from '../../actions'
import { Redirect } from 'react-router';
const Signin = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const auth = useSelector(state => state.auth);
const dispatch = useDispatch();
const userLogin = (e) => {
e.preventDefault();
const user = {
email, password
}
dispatch(signin(user))
}
if(auth.authenticate) {
return <Redirect to={'/'} />
}
return (
<Layout>
<Container>
<Row>
<Col md={{ span: 6, offset: 3 }}>
<Form onSubmit={userLogin}>
<Input
label='Email'
placeholder='Email'
value={email}
type='email'
onChange={(e) => setEmail(e.target.value)}
/>
<Input
label='Password'
placeholder='Password'
value={password}
type='password'
onChange={(e) => setPassword(e.target.value)}
/>
<Button variant='primary' type='submit'>
Submit
</Button>
</Form>
</Col>
</Row>
</Container>
</Layout>
)
}
export default Sign in
axios.js (helpers)
import axios from 'axios';
import { api } from '../../urlConfig';
import store from '../../Store';
import { authConstants } from '../actions/constants';
const token = window.localStorage.getItem('token');
const axiosInstance = axios.create({
baseURL: api,
headers:{
'Authorization': token ? `${token}` : ''
}
});
axiosInstance.interceptors.request.use((req) => {
const { auth } = store.getState();
if(auth.token){
req.headers.Authorization = `${auth.token}`
}
return req;
});
axiosInstance.interceptors.response.use((res) => {
return res;
}, (error) => {
console.log(error.response);
const status = error.response ? error.response.status : 500;
if(status && status === 500) {
localStorage.clear();
store.dispatch({ type: authConstants.LOGOUT_SUCCESS });
}
return Promise.reject(error);
})
export default axiosInstance;
PrivateRoute.js
import React from 'react'
import { Redirect, Route } from 'react-router'
const PrivateRoute = ({ component: Component, ...rest }) => {
return <Route {...rest} component={(props) => {
const token = window.localStorage.getItem('token');
if(token) {
return <Component {...props} />
}else{
return <Redirect to={'signin'} />
}
}} />
}
export default PrivateRoute;
Header.js
import React from 'react';
import Logo from '../../../Logos/main-logo.png';
import { Navbar, Button, Nav } from 'react-bootstrap';
import { NavLink } from 'react-router-dom';
import KeyboardReturnOutlinedIcon from '#material-ui/icons/KeyboardReturnOutlined';
import './style.css';
import { useDispatch, useSelector } from 'react-redux';
import { signout } from '../../actions';
const Header = () => {
const auth = useSelector((state) => state.auth);
const dispatch = useDispatch();
const logout = () => {
dispatch(signout());
}
const renderLoggedInLinks = () => {
return (
<Nav className='host_btn ml-auto'>
<Nav.Link><NavLink className='NavLink' to={`/`}>Home</NavLink></Nav.Link>
<Nav.Link><NavLink className='NavLink ml-2' to={`/about`}>About</NavLink></Nav.Link>
<Nav.Link><NavLink className='NavLink ml-2' to={`/feedback`}>Feedback</NavLink></Nav.Link>
<Nav.Link><NavLink className='NavLink ml-2' onClick={logout}>Signout</NavLink></Nav.Link>
<Button className='ml-5'>Become a host <KeyboardReturnOutlinedIcon /> </Button>
</Nav>
);
};
const renderNonLoggedInLinks = () => {
return (
<Nav className='host_btn ml-auto'>
<Nav.Link><NavLink className='NavLink' to={`/`}>Home</NavLink></Nav.Link>
<Nav.Link><NavLink className='NavLink ml-2' to={`/about`}>About</NavLink></Nav.Link>
<Nav.Link><NavLink className='NavLink ml-2' to={`/feedback`}>Feedback</NavLink></Nav.Link>
<Nav.Link><NavLink className='NavLink ml-2' to={`/signup`}>Signup</NavLink></Nav.Link>
<Nav.Link><NavLink className='NavLink ml-2' to={`/signin`}>Signin</NavLink></Nav.Link>
<Button className='ml-5'>Become a host <KeyboardReturnOutlinedIcon /> </Button>
</Nav>
)
}
return (
<Navbar className='mt-2 ml-2 mr-2' collapseOnSelect expand='sm' bg='light' variant='light'>
<Navbar.Toggle aria-controls='responsive-navbar-nav' />
<Navbar.Collapse id='responsive-navbar-nav' >
<Navbar.Brand className='logo-img' to="#home"><img src={Logo} /></Navbar.Brand>
<Nav className='host_btn ml-auto'>
{auth.authenticate ? renderLoggedInLinks() : renderNonLoggedInLinks()}
</Nav>
</Navbar.Collapse>
</Navbar>
)
}
export default Header

React - Using state in component by useContext

Hello I got stuck during creating app using hooks
I do not why but my Component does not download a state from my Context Component or maybe my initial state does not update correctly. Does somebody have any idea what's going on?
Context Component:
import React, { createContext, useState } from 'react';
export const WeatherDataContext = createContext();
const WeatherDataContextProvider = (props) => {
const [weather, setWeather] = useState(
{
city: null,
temp: null
}
)
const addWeather = (city, temp) => {
setWeather({
city,
temp
})
}
return (
<WeatherDataContext.Provider value={{weather, addWeather}}>
{props.children}
</WeatherDataContext.Provider>
)
}
export default WeatherDataContextProvider
Form - axios - Component:
import React, {useContext, useState} from 'react';
import { WeatherDataContext } from '../context/WeatherDataContext';
import axios from 'axios'
import {Link} from 'react-router-dom'
const WeatherForm = () => {
const {addWeather} = useContext(WeatherDataContext);
const [value, setValue] = useState('')
const handleChange = (e) => {
e.preventDefault();
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${value}&appid=${KEY}&units=metric`)
.then(res => {
addWeather(res.data.name, res.data.main.temp)
})
}
return (
<div class='weather-form'>
<form onSubmit={handleChange}>
<input placeholder='City' onChange={(e) => setValue(e.target.value)} value={value} required/>
<Link to='/weather'><button>Search</button></Link>
</form>
</div>
)
}
export default WeatherForm
And final component where I want to use my update state
import React, {useContext, useState} from 'react';
import { WeatherDataContext } from '../context/WeatherDataContext';
const WeatherFront = () => {
const {weather} = useContext(WeatherDataContext)
console.log(weather)
return (
<div class='weather-front'>
<h1>City: {weather.city}, Temperatura: {weather.temp}</h1>
</div>
)
}
export default WeatherFront
Your button is not submitting the form - it navigates away from the page instead.
So handleChange is not being called.
You can call it from buttons onClick instead of forms onSubmit. Be sure to omit e.preventDefault() then, so that parent Link can still navigate.
const WeatherForm = () => {
const { addWeather } = useContext(WeatherDataContext)
const [value, setValue] = useState('')
const handleChange = (e) => {
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${value}&appid=${KEY}&units=metric`)
.then(res => {
addWeather(res.data.name, res.data.main.temp)
})
}
return (
<div class="weather-form">
<form >
<input
placeholder="City"
onChange={(e) => setValue(e.target.value)}
value={value}
required
/>
<Link to="/weather">
<button onClick={handleChange}>Search</button>
</Link>
</form>
</div>
)
}
Be sure to wrap both pages inside the same context:
<WeatherDataContextProvider>
<Router>
<Switch>
<Route path="/weather">
<WeatherFront></WeatherFront>
</Route>
<Route path="/">
<WeatherForm></WeatherForm>
</Route>
</Switch>
</Router>
</WeatherDataContextProvider>

Resources