Hello today I started working with redux so I am a beginner and I want to make my register request the API Is working perfectly I tested it with postman and also with normal fetch on a component without redux and worked so API is not the problem.
Basically, I want to send user data and get the token back I get 404 not found error in the console here is my code =>
import React, { useState } from 'react';
import './App.css';
import { Provider, connect } from 'react-redux'
import store from './store'
import { register } from './actions/auth'
import PropTypes from 'prop-types';
function App({ register }) {
const [username, setUsername] = useState("")
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
return (
<>
<input placeholder="email" onChange={(e) => { setEmail(e.target.value) }} />
<input placeholder="username" onChange={(e) => { setUsername(e.target.value) }} />
<input placeholder="password" onChange={(e) => { setPassword(e.target.value) }} />
<button onClick={() => { register({ username, password, email }) }}>register</button>
</>
);
}
//todo proptypes
register.PropTypes = {
register: PropTypes.func.isRequired
}
export default connect(null, { register })(App);
// import
import axios from 'axios'
import { REGISTER_FAIL, REGISTER_SUCCESS } from './types'
//register user
export const register = ({ name, email, password }) => async dispatch => {
const config = {
headers: {
"Content-Type": "application/json"
}
}
const body = JSON.stringify({ name, email, password })
try {
const res = await axios.post('http://localhost:3000/api/register', body, config);
dispatch({
type: REGISTER_SUCCESS,
payload: res.data
})
} catch (error) {
dispatch({
type: REGISTER_FAIL
})
}
}
import { REGISTER_FAIL, REGISTER_SUCCESS } from '../actions/types'
const initialState = {
token: localStorage.getItem("token"),
isAuthenticated: null,
user: null
}
export default function (state = initialState, action) {
const { type, payload } = action
switch (type) {
case REGISTER_SUCCESS:
localStorage.setItem("token", payload.token);
return {
...state,
...payload,
isAuthenticated: true
}
case REGISTER_FAIL:
localStorage.removeItem("token");
return {
...state,
token: null,
isAuthenticated: false
};
default:
return state
}
}
Related
I was working on my first MERN project and was trying to use local storage with context API, but the data is not getting reflected in the local storage and no error is getting reflected either in the console.
When I log in as a user, the local storage still stays empty.
Below is my Context.js code
import { createContext, useEffect, useReducer, useState } from "react";
import Reducer from "./Reducer";
const INITIAL_STATE = {
user: JSON.parse(localStorage.getItem("user")) || null,
isFetching: false,
error: false,
};
export const Context = createContext(INITIAL_STATE);
export const ContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(Reducer, INITIAL_STATE);
const [user, setItems] = useState([]);
useEffect(() => {
localStorage.setItem('user', JSON.stringify(state.user));
}, [state.user]);
return (
<Context.Provider
value={{
user: state.user,
isFetching: state.isFetching,
error: state.error,
dispatch,
}}
>
{children}
</Context.Provider>
);
};
Below is my login.jsx code
import { Link } from "react-router-dom";
import "./login.css"
import { useContext, useRef } from "react";
import axios from "axios";
import { Context } from "../../../context/Context";
export default function Login() {
const userRef = useRef();
const passwordRef = useRef();
const { user, dispatch, isFetching } = useContext(Context);
const handleSubmit = async (e) => {
e.preventDefault();
dispatch({ type: "LOGIN_START" });
try {
const res = await axios.post("/auth/login", {
username: userRef.current.value,
password: passwordRef.current.value,
});
dispatch({ type: "LOGIN_SUCCESS", payload: res.data });
} catch (err) {
dispatch({ type: "LOGIN_FAILURE" });
}
};
console.log(isFetching)
return (
<div className="login">
<span className="loginTitle">Login</span>
<form className="loginForm" onSubmit={handleSubmit}>
<label>Username</label>
<input className="loginInput" type="text" placeholder="Enter your username..." ref=
{userRef} />
<label>Password</label>
<input className="loginInput" type="password" placeholder="Enter your
password..."
ref={passwordRef} />
<button className="loginButton" type="submit">Login</button>
</form>
<button className="loginRegisterButton">
<Link className="link" to="/register">Register</Link>
</button>
</div>
);
}
I have tried googling it out for 2 hours straight, but am not able to get the mistake from which it is arising. Any help is highly appreciated!!
import { createContext, useEffect, useReducer, useState } from "react";
import Reducer from "./Reducer";
const INITIAL_STATE = {
user: JSON.parse(localStorage.getItem("user")) || null,
isFetching: false,
error: false,
};
export const Context = createContext(INITIAL_STATE);
export const ContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(Reducer, INITIAL_STATE);
const [user, setItems] = useState([]);
useEffect(() => {
console.log(state.user);
localStorage.setItem('user', JSON.stringify(state.user));
}, [state.user]);
return (
<Context.Provider
value={{
user: state.user,
isFetching: state.isFetching,
error: state.error,
dispatch,
}}
>
{children}
</Context.Provider>
);
};
I think you'd better check first if user data is in there.
I am facing an issue my user is always showing null in the backend, I don't know why.
I am following an Udemy course my tutor is saying middleware is responsible for user identification. but the problem is I typed the same code as my tutor is typing but his codes are working fine mine not.
I am using Axios from the front end to make request.
This my controller ==>
export const currentUser = async (req, res) => {
try {
const user = await User.findById(req._id).select("-password").exec();
console.log("CURRENT_USER", user); return res.json({ ok: true });
} catch (err) {
console.log(err);
}
};
This is my middleware ==>
import { expressjwt } from "express-jwt";
export const requireSignIn = expressjwt({ getToken: (req, res) => req.cookies.token, secret: process.env.JWT_SECRET, algorithms: ["HS256"], }) ;
This my front end code where I have been making request ===>
import { useEffect, useState, useContext } from "react";
import axios from "axios";
import { useRouter } from "next/router";
import { SyncOutlined } from "#ant-design/icons";
import UserNav from "../nav/userNav";
import { Context } from "../../context";
const UserRoutes = ({ children }) => {
const { state: { user } } = useContext(Context);
// state
const [ok, setOk] = useState(false);
// router
const router = useRouter();
useEffect(() => {
fetchUser();
}, []);
const fetchUser = async () => {
try {
const { data } = await axios.get("/api/current-user");
console.log(data);
if (data.ok) setOk(true);
} catch (err) {
console.log(err);
setOk(false);
router.push("/login");
}
};
return (
<>
{!ok ? (
<SyncOutlined spin className="d-flex justify-content-center display-1 text-primary p-5" />
) : (
<div className="UserNavSec">
<div className="UserNavCol1">
<div className="UserNavCont"><UserNav/></div
</div>
<div className="UserNavCol2"> {children} </div
</div>
)}
</>
);
};
export default UserRoutes;
I am learning React Redux. I am having a very difficult time learning it. Please excuse how bad my code is because I only started learning a few days ago I want to have a store for the logged in user. It will contain their username, email, etc. Currently I am not using sessions/cookies nor even a database for the users. I am simply trying to learn Redux.
I need help with a few things. The state can contain many objects. I just want one object for the user. And because I am currently having trouble with that, how do I display the username without having to .map() because the state is an array?
Here is my current code for the actions/reducers.
import { combineReducers } from "redux";
const defaultUser = [];
// Actions
const LOGIN_USER = "LOGIN_USER";
export function loginUser(user) {
return {
type: LOGIN_USER,
user,
};
}
// Reducers
function user(state = defaultUser, action) {
switch (action.type) {
case LOGIN_USER:
return [
...state,
{
username: action.user,
},
];
default:
return state;
}
}
const usersStore = combineReducers({ user });
export default usersStore;
Here is the App.js file where I want a user to type a username in the input box, then print out their username.
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import "./App.css";
import { Sidebar } from "./components/Sidebar/Sidebar";
import { Content } from "./components/Content/Content";
import { loginUser } from "./store";
const App = () => {
const [user, setUser] = useState("");
const selectedUser = useSelector((state) => state.user);
const dispatch = useDispatch();
const handleSubmit = (event) => {
event.preventDefault();
dispatch(loginUser(user));
setUser("");
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={(e) => setUser(e.target.value)}
value={user}
/>
<br />
<input type="submit" />
</form>
<br />
<br />
{selectedUser.map((selectUser) => (
<li key={selectUser.username}>
<h3>{selectUser.username}</h3>
</li>
))}
<Content />
</div>
);
};
I figured it out on my own. With my new setup, all I have to do is type {user.username} to get the username of the logged in user. I am fetching it with useSelector().
It basically sets the username as a state temporarily, then sends it over to the store via dispatch, then empties out the state afterwards.
I had to change the initialstate to an object with "profile" inside it (instead of using an array)
I then had to map the state to props of the component I want it to display in, using a function, and then use connect() when exporting it.
Here's my new component code, the bottom few lines are the most important:
import React, { useState } from "react";
import { connect, useDispatch, useSelector } from "react-redux";
import "./App.css";
import { Sidebar } from "./components/Sidebar/Sidebar";
import { Content } from "./components/Content/Content";
import { loginUser } from "./store";
const App = (props) => {
const [stateUser, stateSetUser] = useState("");
const user = useSelector((state) => state.user.profile);
const dispatch = useDispatch();
const handleSubmit = (event) => {
event.preventDefault();
dispatch(loginUser(stateUser));
stateSetUser("");
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={(e) => stateSetUser(e.target.value)}
/>
<input type="submit"></input>
</form>
{user.username}
<Content />
</div>
);
};
const mapStateToProps = (state) => {
return {
profile: state.user.profile,
};
};
export default connect(mapStateToProps)(App);
My reducer/actions file: (changes in initialstate are most important)
import { combineReducers } from "redux";
const initialState = {
profile: {
username: "",
email: "",
profileImage: "",
},
};
// Actions
const LOGIN_USER = "LOGIN_USER";
export function loginUser(user) {
return {
type: LOGIN_USER,
user,
};
}
// Reducers
function user(state = initialState, action) {
switch (action.type) {
case LOGIN_USER:
return {
...state,
profile: { username: action.user },
};
default:
return state;
}
}
const usersStore = combineReducers({ user });
export default usersStore;
Im followin a youtube tutorial to do payments but I am stucked at a pace that axios could not post data to server
code
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Abc from './Abc';
import './index.css'
ReactDOM.render(
<Abc/>
,
document.getElementById('root')
);
Abc.js
import React from "react";
import { loadStripe } from "#stripe/stripe-js";
import {
Elements,
CardElement,
useStripe,
useElements
} from "#stripe/react-stripe-js";
import axios from "axios";
const CheckoutForm = ({ success }) => {
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async event => {
event.preventDefault();
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: "card",
card: elements.getElement(CardElement)
});
if (!error) {
const { id } = paymentMethod;
try {
const { data } = await axios.post("/api/charge", { id, amount: 1099 });
console.log(data);
success();
} catch (error) {
console.log('error is => ',error);
}
}
};
return (
<form
onSubmit={handleSubmit}
style={{ maxWidth: "400px", margin: "0 auto" }}
>
<h2>Price: $10.99 USD</h2>
<img
src="https://images.ricardocuisine.com/services/recipes/500x675_7700.jpg"
style={{ maxWidth: "50px" }}
alt='abc'
/>
<CardElement />
<button type="submit" disabled={!stripe}>
Pay
</button>
</form>
);
};
// you should use env variables here to not commit this
// but it is a public key anyway, so not as sensitive
const stripePromise = loadStripe("pk_test_51JsQsfBbWBJ638dRkTi29yzu85fW6JAvGzbJo9f5RgOtOogcpKnzCfJo6VJoKGemEW54wxrDebWpM8V6vKJl36mC00K3JPAmHr");
const Abc = () => {
const [status, setStatus] = React.useState("ready");
if (status === "success") {
return <div>Congrats on your empanadas!</div>;
}
return (
<Elements stripe={stripePromise}>
<CheckoutForm
success={() => {
setStatus("success");
}}
/>
</Elements>
);
};
export default Abc;
charge.js
import Stripe from "stripe";
const stripe = new Stripe("sk_test_51JsQsfBbWBJ638dRR3Iryb907XNtHaeVYhtCRp6SDmaiWmQg51ys2wdB3z6HJ8svutnA8HPMp5yEtdxTSParn3uN00Xb3PJd4o");
export default async (req, res) => {
const { id, amount } = req.body;
try {
const payment = await stripe.paymentIntents.create({
amount,
currency: "USD",
description: "Delicious empanadas",
payment_method: id,
confirm: true
});
console.log(payment);
return res.status(200).json({
confirm: "abc123"
});
} catch (error) {
console.log(error);
return res.status(400).json({
message: error.message
});
}
};
but this is giving me error when submitting xhr.js:210 POST http://localhost:3000/api/charge 404 (Not Found)
Hierarchy
any help will be appreciated.I was following https://www.youtube.com/watch?v=WTUYem2IxLA&ab_channel=LeighHalliday tutorial
Assuming you have Next.js set up properly, your api folder needs to be in the /pages directory.
https://nextjs.org/docs/api-routes/introduction
handleSubmit() isn't sending form data. It appears the configuration object for the fields are undefined for some reason, even though i believe i wired up redux-form correctly.
LoginComponent.js
import { reduxForm } from 'redux-form';
import '../others/styles.css';
const FIELDS = {
username: {
type: 'input',
label: 'Enter username'
},
password: {
type: 'input',
label: 'Enter password'
}
};
const Login = (props) => {
console.log('--------- props: ', props);
const { fields: { username, password }, handleSubmit, setUsernameAndPassword } = props;
console.log('-------- username: ', username); // PROBLEM: Returns undefined when it should return the config object for this field
return (
<div>
<Form onSubmit={ handleSubmit(setUsernameAndPassword.bind(this)) } id='login'>
<Form.Field>
<label>Username</label>
<input {...username}
name='username' />
</Form.Field>
....
Login.propTypes = {
handleSubmit: React.PropTypes.func,
fields: React.PropTypes.array,
setUsernameAndPassword: React.PropTypes.func
};
export default reduxForm({
form: 'LoginForm',
fields: Object.keys(FIELDS)
})(Login);
LoginContainer.js
import { connect } from 'react-redux';
import { graphql } from 'react-apollo';
import Login from '../components/LoginComponent';
import LoginMutation from '../graphql/LoginMutation.gql';
import { types as typesAuth } from '../reducers/auth';
const gqlLogin = graphql( LoginMutation, {
props: ({mutate}) => ({
login: async function loginWithUsernameOrEmail(variables) {
try {
const result = await mutate({variables});
} catch (err) {
console.log('GQL Error: ', err);
}
}
})
})(Login);
export default connect(
state => ({
isLoggedIn: state.auth.isLoggedIn
}),
dispatch => ({
setUsernameAndPassword: (data) => { // PROBLEM: Why is data empty??
console.log('--------- data: ', data);
dispatch({
type: typesAuth.SET_USERNAME_PASSWORD,
payload: {
username: data.username,
password: data.password
}
});
}
}),
)(gqlLogin);
reducers/index.js
import { reducer as auth } from './auth';
import { reducer as formReducer } from 'redux-form';
export default {
auth,
form: formReducer
};
reducers.js
// Modules
import appReducers from '../modules/root/reducers/';
import authReducers from '../modules/auth/reducers/';
module.exports = {
...appReducers,
...authReducers
};
redux.js
// Imports
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
// Reducers
import Client from './client';
import reducers from './reducers';
const devtools = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
module.exports = createStore(
combineReducers({
...reducers,
apollo: Client.reducer()
}),
compose(
applyMiddleware(Client.middleware()), devtools()
),
);
auth.js
// Constants
export const types = Object.freeze({
SET_USERNAME_PASSWORD: 'AUTH/SET_USERNAME_PASSWORD'
});
// Default State
const DEF_STATE = {
isLoggedIn: false,
username: null,
password: null
};
export const reducer = (state = DEF_STATE, action) => {
let newState;
switch (action.type) {
...
case types.SET_USERNAME_PASSWORD:
newState = {
...state,
username: action.payload.username,
password: action.payload.password
};
break;
default:
newState = state;
}
return newState;
};
You need to use Field components from redux-form to tie the individual inputs to the redux store (see docs).
The "Simple Form" Example in the redux-form docs is a good demonstration of how to do this, simply import the Field component from redux-form and use it to describe your inputs. In your case it would be something like this:
import { reduxForm, Field } from 'redux-form';
const Login = (props) => {
console.log('--------- props: ', props);
const { handleSubmit, isLoggingIn, setUsernameAndPassword } = props;
return (
<div>
<Form onSubmit={ handleSubmit(setUsernameAndPassword.bind(this)) } id='login'>
<Form.Field>
<label>{i18n.t('auth.username')}</label>
<Field
component="input"
name="username"
placeholder={i18n.t('utils.and',{item1: i18n.t('auth.username'), item2: i18n.t('auth.email')})}
/>
</Form.Field>
....
Hope this helps!