Converting function React component to class component - node.js

I'm trying to add a login page to my existing app. Following along this tutorial https://www.digitalocean.com/community/tutorials/how-to-add-login-authentication-to-react-applications
Got stuck in step 3. My app is a class component, while in the tutorial it's a function component.
How can I convert this to a class component?
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import './App.css';
import Dashboard from '../Dashboard/Dashboard';
import Login from '../Login/Login';
import Preferences from '../Preferences/Preferences';
function setToken(userToken) {
sessionStorage.setItem('token', JSON.stringify(userToken));
}
function getToken() {
const tokenString = sessionStorage.getItem('token');
const userToken = JSON.parse(tokenString);
return userToken?.token
}
function App() {
const token = getToken();
if(!token) {
return <Login setToken={setToken} />
}
return (
<div className="wrapper">
...
</div>
);
}
export default App;
I've tried as below, but it says getToken is not defined inside of a render.
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import './App.css';
import Dashboard from '../Dashboard/Dashboard';
import Login from '../Login/Login';
import Preferences from '../Preferences/Preferences';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
token: undefined
}
this.setToken = this.setToken.bind(this);
this.getToken = this.getToken.bind(this);
}
setToken(userToken) {
sessionStorage.setItem('token', JSON.stringify(userToken));
}
getToken() {
const tokenString = sessionStorage.getItem('token');
const userToken = JSON.parse(tokenString);
return userToken?.token;
}
render() {
const {token} = getToken(); /* In this line getToken is not defined */
if (!token) {
return <Login setToken={(newToken) => this.setState({ token: newToken })} />
}
return (
<div className="pomodoro-clock">
</div>
);
}
I see in the original code, getToken and setToken declared outside of an app. I've tried this, but anyway, getToken is not defined .
I can provide the full code if needed. Any help is appreciated.

If you want to make the functions members of the class, then you need to refer to it using this.getToken(), not just getToken();
render() {
const {token} = this.getToken();
Though since the getToken and setToken functions don't make any reference to this they don't actually need to part of the class. You could keep them outside the class, and refer to them the same way the function component refers to them:
function setToken(userToken) {
sessionStorage.setItem('token', JSON.stringify(userToken));
}
function getToken() {
const tokenString = sessionStorage.getItem('token');
const userToken = JSON.parse(tokenString);
return userToken?.token
}
export default class App extends Component {
constructor(props) {
super(props);
}
render() {
const {token} = getToken();
// ...
}
}

Related

useContext auth hook returning null

I have created a useAuth hook in order to allow the user access to the private route once authorised the authorising cookie is stored properly but the useAuth hook seems to be returning null. I also tried printing the value of setUser but it doesn't seem to print after the line setUser(res.data.currentUser) but the one before is printed I cannot figure out why.
The cookies are stored and set properly it just seems to be the auth hook that return setUser as null even though the line console.log("RES>DATA = ", res.data.currentUser); logs the correct details of the cookie but when I try to manually change the url to the private route after the cookie is stored it returns a null for the setUser returned from the auth hook and so access to private route isn't granted. This is done using react for frontend with node js and express for the backend. If any more context is necessary please let me know.
useAuth hook:
import { useState, useContext, useEffect } from "react";
import { UserContext } from "./UserContext";
import axios from "axios";
export default function useAuth() {
const { setUser } = useContext(UserContext);
const [error, setError] = useState(null);
useEffect(() => {
console.log("USE effect");
setUserContext();
});
//set user in context and push them home
const setUserContext = async () => {
console.log("In here");
return await axios
.get("auth/checkAuth")
.then((res) => {
console.log("RES>DATA = ", res.data.currentUser); // PRINTS THE CORRECT COOKIE VALUES
setUser(res.data.currentUser); // THIS SEEMS TO BE NULL?????
console.log("SET USER + ", setUser); // THIS DOES NOT PRINT
})
.catch((err) => {
setError(err);
});
};
return {
setUser,
};
}
Private route:
import React, { useContext } from 'react';
import {Route, Redirect, Navigate} from 'react-router-dom';
import { UserContext } from '../hooks/UserContext';
import useAuth from '../hooks/useAuth';
export default function PrivateRoute({children}) {
const auth = useAuth();
console.log("aUTH in priv = ", auth);
return auth ? children : <Navigate to="/"/>
}
App.js:
import "./App.css";
import { Redirect, Route, Routes, Switch } from "react-router-dom";
import useFetch from "./useFetch";
import { useEffect, useState, useRef } from "react";
import axios from "axios";
import Activities from "./components/Activities";
import HomePage from "./components/Home";
import Map from "./components/Map";
import checkUser from "./hooks/checkUser";
import { UserContext } from "./hooks/UserContext";
import useFindUser from "./hooks/checkUser";
import PrivateRoute from "./components/PrivateRoute";
function App() {
const [auth, setAuth] = useState(false);
const [activities, setActivities] = useState([]);
const notInitialRender = useRef(false);
const { user, setUser, isLoading } = useFindUser(); // works as expected
return (
<div className="App">
<UserContext.Provider value={{ user, setUser, isLoading }}>
<Routes>
<Route path="/" element={<HomePage />}></Route>
<Route path="/Activities" element={<Activities />} />
<Route
path="/Private"
element={
<PrivateRoute>
<Map />
</PrivateRoute>
}
/>
</Routes>
</UserContext.Provider>
</div>
);
}
export default App;
auth/checkAuth express route:
export const checkAuth = (req, res) => {
let currentUser;
console.log("res.cookies = ", req);
if (req.cookies.currentUser) {
// res.send(200);
currentUser = req.cookies.currentUser; // set to user object in cookies
console.log("current user = ", currentUser);
// return 200 status code
} else {
currentUser = null;
}
//res.json(currentUser);
res.status(200).send({ currentUser });
};
Map component which is private route component:
import react from 'react';
function Map() {
<div>
<p style={{color:'red'}}>You have access to the private route</p>
</div>
}
export default Map;
UserContext file:
import { createContext } from "react";
export const UserContext = createContext("null");
I tried logging values and using useEffect to call the function when the useAuth hook is called but couldn't figure it out

React useState can't use from another component

I Created a node.js server and i can write user info to MongoDb and i can create JWT in postman. so i want to use this on react project.
i created react router with private route which it's checking if there is an any user info in the local storage. example , (i did not create a axios post for login api. i just want to write user info with hardcode for see the code is working)
import { useAuth } from "../Context/AuthContext";
import { Navigate,useLocation } from "react-router-dom";
export default function PrivateRoutes({children}){
const user = JSON.parse(localStorage.getItem('user'))
const location = useLocation();
if(!user){
return <Navigate to="/login" state={{return_url:location.pathname}} />
}
return children;
}
authcontext
So , when i'm in a login page , i created a button and if i click this button i want to access to my AuthProvider and set user info to the LocalStorage in AuthProvider.
Login page,
LoginPage.js
import { useAuth } from "../../../Context/AuthContext";
import { useNavigate,useLocation } from "react-router-dom";
export default function LoginPage(){
const navigate = useNavigate();
const location = useLocation();
const { setUser } = useAuth();
const loginHandle = () => {
setUser({
id : 1,
username : 'umitcamurcuk'
})
navigate(location?.state?.return_url || '/');
}
const logoutHandle = () => {
setUser(false);
navigate('/');
}
return (
<div>
<button onClick={loginHandle}>Sign In</button>
<button onClick={logoutHandle}>Cikis yap</button>
</div>
)
}
and my AuthContext page,
AuthContext.js
import { createContext, useState , useContext, useEffect } from "react";
const Context = createContext()
export const AuthProvider = ({ children }) => {
const [user , setUser] = useState(JSON.parse(localStorage.getItem('user')) || false);
const data = [ user, setUser ]
useEffect(() => {
localStorage.setItem('user', JSON.stringify(user))
},[user])
return(
<Context.Provider value={data}>
{children}
</Context.Provider>
)
}
export const useAuth = () => useContext(Context);
But when i click login button , this error show up
error
LoginPage.js:12 Uncaught TypeError: setUser is not a function
and my indexJS
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {BrowserRouter} from 'react-router-dom';
import { AuthProvider } from './Context/AuthContext.js';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<AuthProvider>
<App />
</AuthProvider>
</BrowserRouter>
);
is anyone for help me ?
Thanks
You defined your value as array and not an object
const [user, setUser] = useAuth();
or
const data = { user, setUser }

React js how to set and get parameter from another file?

i'm new in react, and i would like to ask about how to send parameter to another function in class component. For example :
Main.js
import React, { Component } from "react";
import Form from "./Form";
import fetchData from "./Action";
export default class Main extends Component {
constructor(props) {
super(props);
this.fetchingData = this.fetchingData.bind(this);
this.state = {
list: 0
};
}
fetchingData(x) {
const data = fetchData(); // => from Action.js (get the return)
this.setState({ list: data });
}
componentDidMount(){
this.fetchingData();
}
render() {
return (
<>
<h3>Data</h3>
<Form />
<p>result: {this.state.list}</p> //=>show the result and auto update when click by button
</>
);
}
}
Form.js
import React from "react";
import fetchData from "./Action";
function Form() {
const handlerClick = (v) => {
fetchData(v); //=>set value form this function (from action.js)
};
return (
<>
<button onClick={(e) => handlerClick(1)}>Push</button>
</>
);
}
export default Form;
Action.js
const fetchData = (v) => {
return v;
};
export default fetchData;
From that code i would like to send parameter from button handlerClick() inside of that function, there is fetchData(), this function will keep the param and return it to the Main.js for fillup the setState. And the result will auto updated, when click the button Push.
Would u like to help me fixing my code ?
You have to send the function fetchingData as a prop to Form, something like: <Form fetchingData={fetchingData} /> from Main.js, that way you can call the function from <Form /> component and have your value saved.
Main.js
import React, { Component } from "react";
import Form from "./Form";
import fetchData from "./Action";
export default class App extends Component {
constructor(props) {
super(props);
this.fetchingData = this.fetchingData.bind(this);
this.state = {
list: 0
};
}
fetchingData(x) {
const data = fetchData(x); // => from Action.js (get the return)
this.setState({ list: data });
}
componentDidMount() {
this.fetchingData();
}
render() {
return (
<>
<h3>Data</h3>
<Form fData={this.fetchingData} />
<p>result: {this.state.list}</p>
</>
);
}
}
Form.js
import React from "react";
import fetchData from "./Action";
const Form = (props) => {
const handlerClick = (v) => {
if (props.fData) {
props.fData(v);
} else {
fetchData(v); //=>set value form this function (from action.js)
}
};
return (
<>
<button onClick={(e) => handlerClick(10)}>Push</button>
</>
);
};
export default Form;
Action.js
const fetchData = (v) => {
return v;
};
export default fetchData;
Live Demo

TypeError: Cannot read property 'map' of undefined in reactjs

I'm working on an app with expressjs and reactjs. I fetched the data from the backend using expressjs but I get map is not a function.
import React, { Component } from "react";
import "./products.css";
import Listofproducts from "./listofproducts";
import { Link } from "react-router-dom";
class products extends Component {
constructor(props) {
super(props);
this.state = {
productInfo: ""
};
}
async getProducts() {
try {
const data = await fetch("http://localhost:4000/product");
const jsonData = await data.json();
this.setState({
productInfo: jsonData
});
console.log(this.state.productInfo);
} catch (error) {
console.log(error);
}
}
componentDidMount() {
this.getProducts();
}
render() {
return (
<React.Fragment>
<Listofproducts itemlists={this.state.productInfo} />
</React.Fragment>
);
}
}
export default products;
Here is the component productLists where I sent the props to work with it.
import React, { Component } from "react";
import Product from "./products";
class Listofproducts extends Component {
render() {
const { itemslist } = this.props;
console.log(itemslist);
// console.log is working here i get back the data on the console
return itemslist.map(list => {
console.log(list);
});
}
}
export default Listofproducts;
You set productInfo to an empty string in the constructor of products, and strings don't have a map method.
Change the default value to an empty array instead and it will work just as well before and after your network request completes.
class Products extends Component {
constructor(props) {
super(props);
this.state = {
productInfo: []
};
}
// ...
}

getInitialProps does not work when the page reload

I'm using getInitialProps in the _app.js component, but when I reload the page, the request does not execute.
For example:
// getData.js
import * as axios from 'axios';
export default async function getData() {
const response = await axios.get('http://someapi.com/');
return response.data;
}
And then I'm going to use that data...
// _app.js
import getData from './getData';
import App, { Container } from "next/app";
class MyApp extends App {
static async getInitialProps() {
const response = await getData();
if (response) {
return { response };
}
return {};
}
render() {
const { Component, response } = this.props;
<Container>
<Component {...this.props} data={response} />
</Container>
}
}
The first time, it works perfectly, but when I reload the page the getInitialProps() function does not executes :(
How can I resolve this?
Thank you.

Resources