Match Params Id not working, how to fix it? - reactjs

So i'm trying to access the id of my ypdate, and the example code i fould uses Match, I don't think the newer version of React likes it. I think I need to implement useParams(), however I new to coding and i'm not sure how to. Here is my code with Match params
import { useEffect } from "react";
import { Redirect } from "react-router-dom";
import { PlusCircleIcon, BookOpenIcon } from "#heroicons/react/solid";
import { useFormik } from "formik";
import * as Yup from "yup";
import { useDispatch, useSelector } from "react-redux";
import {
fetchCategoryAction,
updateCategoriesAction,
deleteCategoriesAction,
} from "../../redux/slices/category/categorySlice";
//Form schema
const formSchema = Yup.object({
title: Yup.string().required("Title is required"),
});
const UpdateCategory = ({
match: {
params: { id },
},
}) => {
const dispatch = useDispatch();
//fetch single category
useEffect(() => {
dispatch(fetchCategoryAction(id));
}, []);
//get data from store
const state = useSelector(state => state?.category);
const { loading, appErr, serverErr, category, isEdited, isDeleted } = state;
//formik
const formik = useFormik({
enableReinitialize: true,
initialValues: {
title: category?.title,
},
onSubmit: values => {
//build up the date for update
//dispath the action
dispatch(updateCategoriesAction({ title: values.title, id }));
},
validationSchema: formSchema,
});
//redirect
if (isEdited || isDeleted) return <Redirect to="/category-list" />;
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-md w-full space-y-8">
<div>
<BookOpenIcon className="mx-auto h-12 w-auto" />
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
Update Category
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
<p className="font-medium text-indigo-600 hover:text-indigo-500">
These are the categories user will select when creating a post
</p>
{/* Display err */}
<div>
{appErr || serverErr ? (
<h2 className="text-red-500 text-center text-lg">
{serverErr} {appErr}
</h2>
) : null}
</div>
</p>
</div>
{/* Form */}
<form onSubmit={formik.handleSubmit} className="mt-8 space-y-6">
<input type="hidden" name="remember" defaultValue="true" />
<div className="rounded-md shadow-sm -space-y-px">
<div>
<label htmlFor="email-address" className="sr-only">
Name
</label>
{/* Title */}
<input
value={formik.values.title}
onChange={formik.handleChange("title")}
onBlur={formik.handleBlur("title")}
type="text"
autoComplete="text"
className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 text-center focus:z-10 sm:text-sm"
placeholder="New Category"
/>
<div className="text-red-400 mb-2">
{formik.touched.title && formik.errors.title}
</div>
</div>
</div>
<div>
<div>
{/* Submit */}
{loading ? (
<button
disabled
className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-gray-600 "
>
<span className="absolute left-0 inset-y-0 flex items-center pl-3">
<PlusCircleIcon
className="h-5 w-5 text-yellow-500 group-hover:text-indigo-400"
aria-hidden="true"
/>
</span>
Loading please wait...
</button>
) : (
<>
<button
type="submit"
className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-yellow-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
<span className="absolute left-0 inset-y-0 flex items-center pl-3">
<PlusCircleIcon
className="h-5 w-5 text-yellow-500 group-hover:text-indigo-400"
aria-hidden="true"
/>
</span>
Update Category
</button>
<button
onClick={() => dispatch(deleteCategoriesAction(id))}
type="submit"
className="group mt-2 relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-red-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Delete Category
</button>
</>
)}
</div>
</div>
</form>
</div>
</div>
);
};
export default UpdateCategory;
Nothing renders to the screen with it in there I take it out and I do, however the functionality i need for updating isn't there. Any help would be greatly appreciated.

Related

reactjs remember me functionality on localstorage

I'm having a problem here when creating a remember me function in Reactjs.
So, I managed to enter the username, password and isChecked into localstorage.
However, when I logged out, all the data in the local storage was deleted including the username, password and isChecked.
How do you make the username, password and isChecked persist after logging out? Thank You
MyCode =
import React, { useState } from "react";
import Logo from "../../../../assets/images/logo.png";
import BackgroundProfile from "../../../../assets/images/background-profile.png";
import { VscKey } from "react-icons/vsc";
import { Link } from "react-router-dom";
import { signin } from "../../../../service/account";
import { toast } from "react-toastify";
export default function CardLogin(props) {
const {
labelText,
inputText,
loginType,
firstOptionLogin,
secondOptionLogin,
labelIcon,
firstRoute,
secondRoute,
firstIcon,
secondIcon,
} = props;
const [username, setUsername] = useState(() =>
localStorage.checkbox ? localStorage.username : ""
);
const [password, setPassword] = useState(() =>
localStorage.checkbox ? localStorage.password : ""
);
const [isChecked, setIsChecked] = useState(() => !!localStorage.checkbox);
const initialValue = {
username: username,
password: password,
nik: "",
};
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = () => {
if (isChecked && username !== "") {
localStorage.username = username;
localStorage.password = password;
localStorage.checkbox = isChecked ? "1" : "";
}
const data = new URLSearchParams();
console.log(loginType);
if (loginType === "username") {
data.append("username", initialValue.username);
data.append("password", initialValue.password);
data.append("grant_type", "password");
}
setIsLoading(true);
signin(data, loginType)
.then((response) => {
if (response?.code === 200) {
console.log(response);
localStorage.setItem(
"accessToken",
JSON.stringify(response.data.accessToken)
);
localStorage.setItem(
"userSession",
JSON.stringify(response.data.accessTokenExpiresAt)
);
window.location.reload();
} else {
toast.error(response.message);
}
})
.catch((error) => {
console.log(error);
})
.finally(() => {
setIsLoading(false);
});
};
return (
<div
style={{
backgroundSize: "100% 75%",
backgroundRepeat: "no-repeat",
height: "100%",
backgroundImage: `url(${BackgroundProfile})`,
}}
>
{/* Button Back on The Top of Page */}
<button>
<div className="rounded-full w-5 md:w-10 h-5 md:h-10 p-3 relative top-2 left-2">
{/* <FaArrowLeft className="text-[#DD2729] text-xs md:text-base absolute top-1/2 left-1/2 -translate-y-1/2 -translate-x-1/2" /> */}
</div>
</button>
{/* Logo & Card Login */}
<img
src={Logo}
className="absolute top-6 bottom-6 right-4 w-2/5 md:w-1/5"
alt="Logo"
/>
<div className="mx-auto mt-8 w-3/5 md:w-2/5 bg-white px-5 py-3 md:px-8 md:py-5 rounded-md drop-shadow-xl">
<button>
{/* <FaArrowLeft className="text-[#DD2729] text-xs md:text-base" /> */}
</button>
<article
style={{ fontFamily: "ubuntu" }}
className="text-center text-[#808285] text-xs md:text-lg"
>
Selamat Datang! <br /> Silakan masuk untuk mulai menggunakan aplikasi
</article>
{/* Form Login*/}
<form onSubmit={handleSubmit} className="pt-3 md:pt-5">
<div>
<label
htmlFor={loginType}
className="text-[#424242] text-xs md:text-sm "
>
{labelText}
</label>
<div className="flex">
<div
className={`w-10 flex items-center justify-center bg-blue-lighter border-y border-l border-[#9E9E9E] rounded-l text-blue-dark`}
>
{labelIcon}
</div>
<input
id="username"
name="username"
type="text"
placeholder={inputText}
value={username}
onChange={(e) => setUsername(e.target.value)}
className={`w-full border-l-0 border-[#9E9E9E] rounded-r text-xs md:text-lg font-sans`}
/>
</div>
</div>
<div className="pt-2 md:pt-3">
<label
htmlFor="password"
className="text-[#424242] text-xs md:text-sm"
>
Password
</label>
<div className="flex">
<div
className={`w-10 flex items-center justify-center bg-blue-lighter border-y border-l border-[#9E9E9E] rounded-l text-blue-dark `}
>
<VscKey className="text-[#A8A8A8] text-xl" />
</div>
<input
id="password"
name="password"
type="password"
placeholder="Masukkan kata sandi anda"
value={password}
onChange={(e) => setPassword(e.target.value)}
className={`w-full border-l-0 border-[#9E9E9E] rounded-r text-xs md:text-lg font-normal `}
/>
</div>
</div>
{/* End of Form Login */}
{/* Remember me & Forgot Password */}
<div className="flex pt-3 items-center justify-between">
<div className="flex items-center gap-1.5">
<input
type="checkbox"
checked={isChecked}
name="lsRememberMe"
onChange={(e) => setIsChecked(e.target.checked)}
className="rounded"
/>
<label htmlFor="" className="text-xs md:text-sm">
Remember me
</label>
</div>
<div className="">
<Link
to="/forgot-password"
className="text-xs md:text-sm underline underline-offset-1 font-bold"
>
Forgot password
</Link>
</div>
</div>
<input
type="submit"
value={isLoading ? "Loading" : "Masuk"}
disabled={isLoading}
className="bg-[#EA001E] hover:bg-[#F55151] active:bg-[#BA0D0D] w-full text-white font-bold text-md rounded-lg p-2 mt-4 shadow-xl cursor-pointer text-xs md:text-sm"
/>
</form>
{/* End of Remember me & Forgot Password */}
{/* Login Option */}
<div className="mt-3">
<h4 className="login-selection text-center text-xs md:text-sm">
or login with
</h4>
</div>
<div className="flex items-center justify-center gap-2 mt-4">
<Link to={firstRoute}>
<div className="flex items-center justify-around gap-2 bg-white shadow-xl rounded-full py-2 px-3 md:px-8">
<img
src={firstIcon}
alt="Login Icons"
className="w-2/6 md:w-4/5"
/>
<div className="font-bold text-xs md:text-sm uppercase">
{firstOptionLogin}
</div>
</div>
</Link>
<Link to={secondRoute}>
<div className="flex items-center justify-around gap-2 bg-white shadow-xl rounded-full py-2 px-3 md:px-10">
<img
src={secondIcon}
alt="Login Icons"
className="w-2/6 md:w-4/5"
/>
<div className="font-bold text-xs md:text-sm uppercase">
{secondOptionLogin}
</div>
</div>
</Link>
</div>
{/* End of Login Option */}
{/* Alternative Register */}
<div className="flex items-center justify-center gap-2 mt-4 text-xs md:text-sm">
<p>Don't have an account?</p>
<Link
to="/signup"
className="text-[#DE1B1B] font-bold text-xs md:text-sm"
>
Sign Up
</Link>
</div>
{/* End of Alternative Register */}
</div>
</div>
);
}
CASE CLOSED, in the form section onSubmit={handleSubmit} I delete it to just form, then onSubmit={handleSubmit} I move it to button to become onClick={handleSubmit}.
thank you for answering my question. i appreciate it

I'm using Tailwind in a React project. How do I successfully get the modal to fully go away after submitting? It seems that it's still greyed out

Here is my Signup.js
import React from "react";
import { useToken } from "./AuthenticateUser";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
export default function Signup() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [first_name, setFirst] = useState("");
const [last_name, setLast] = useState("");
const [zipcode, setZip] = useState("");
const [errorMessage, setErrorMessage] = useState("");
const navigate = useNavigate();
const [, , , signup] = useToken();
const modal = document.getElementById("signup");
const handleFormSubmit = async (e) => {
e.preventDefault();
if (formValidation() === false) {
return;
}
signup(first_name, last_name, email, zipcode, password);
setEmail("");
setPassword("");
setFirst("");
setLast("");
setZip("");
navigate("/me");
setErrorMessage("");
modal.classList.remove("show");
};
function formValidation() {
let blankInputs = 0;
if (email.length === 0) {
blankInputs++;
}
if (password.length === 0) {
blankInputs++;
}
if (first_name.length === 0) {
blankInputs++;
}
if (last_name.length === 0) {
blankInputs++;
}
if (zipcode.length === 0) {
blankInputs++;
}
if (blankInputs === 5) {
setErrorMessage("Form submission is completely blank.");
return false;
}
if (blankInputs > 1) {
setErrorMessage("Form has multiple blank inputs.");
return false;
}
if (!validateEmail()) {
setErrorMessage("Whoops! Email format is invalid.");
return false;
}
if (zipcode.length < 5) {
setErrorMessage("Whoops! Zipcode needs to be at least 5 characters");
return false;
}
if (!password) {
setErrorMessage("Whoops! Password is required.");
return false;
}
if (!first_name) {
setErrorMessage("Whoops! First name is required.");
return false;
}
if (!last_name) {
setErrorMessage("Whoops! Last name is required.");
return false;
}
return true;
}
function validateEmail() {
const regex =
/^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return regex.test(String(email).toLowerCase());
}
return (
<>
<div
className="modal fade fixed top-0 left-0 hidden w-full h-full outline-none overflow-x-hidden overflow-y-auto"
id="signup"
tabIndex="-1"
aria-labelledby="signupLabel"
aria-modal="true"
role="dialog"
>
<div className="modal-dialog modal-dialog-centered relative w-auto pointer-events-none">
<div className="modal-content border-none shadow-lg relative flex flex-col w-full pointer-events-auto bg-[#F0C797] bg-clip-padding rounded-md outline-none text-current">
<div className="modal-header p-6 mt-2 text-center">
<div className="flex justify-center items-center">
<h1 className="text-3xl font-bold mr-4">SIGN UP</h1>
<img src={require("../images/checklist.png")} width="50px" />
</div>
<svg
className="w-9 h-9 absolute top-3 right-2.5 text-black bg-transparent rounded-lg text-sm p-1.5 ml-auto inline-flex items-center hover:bg-[#FEF5ED] hover:text-white ease-linear transition-all duration-150 cursor-pointer"
fillRule="currentColor"
data-bs-dismiss="modal"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clipRule="evenodd"
></path>
</svg>
</div>
<div className="modal-body relative p-4">
<form
onSubmit={handleFormSubmit}
className="container max-w-sm mx-auto flex-1 flex flex-col items-center justify-center px-3"
>
<input
type="text"
className="block border border-grey-light w-full p-3 rounded mb-4 placeholder:text-sm"
placeholder="First Name"
onChange={(e) => setFirst(e.target.value)}
value={first_name}
/>
<input
type="text"
className="block border border-grey-light w-full p-3 rounded mb-4 placeholder:text-sm"
placeholder="Last Name"
onChange={(e) => setLast(e.target.value)}
value={last_name}
/>
<input
type="email"
className="block border border-grey-light w-full p-3 rounded mb-4 placeholder:text-sm"
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}
value={email}
/>
<input
type="text"
className="block border border-grey-light w-full p-3 rounded mb-4 placeholder:text-sm"
placeholder="Zipcode"
onChange={(e) => setZip(e.target.value)}
value={zipcode}
/>
<input
type="password"
className="block border border-grey-light w-full p-3 rounded mb-4 placeholder:text-sm"
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
value={password}
/>
{errorMessage ? (
<div className="flex p-4 mb-4 text-sm text-red-700 border border-red-300 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400 dark:border-red-800 items-center">
<img
src={require("../images/warning.png")}
width="30px"
style={{ marginRight: "15px" }}
/>
{errorMessage}
</div>
) : null}
<div className="flex flex-col items-center justify-end p-3 border-solid border-slate-200 rounded-b">
<button
// data-bs-dismiss="modal"
className="bg-black text-white font-bold uppercase text-sm px-6 py-3 rounded inline-flex group items-center justify-center cursor-pointer"
>
<span className="absolute w-0 h-0 transition-all duration-300 ease-out bg-[#F0C797] group-hover:w-32 group-hover:h-24 opacity-10"></span>
Order up!
</button>
</div>
</form>
<div className="flex items-center">
<a
data-bs-toggle="modal"
data-bs-target="#login"
className="mb-6 mt-4 mx-auto text-black-500 background-transparent font-bold underline uppercase text-sm focus:outline-none ease-linear transition-all duration-150 hover:text-white cursor-pointer"
>
Already have an account?
</a>
</div>
</div>
</div>
</div>
</div>
</>
);
}
**
Here is my Nav.js**
mport { useState } from "react";
function Nav() {
let [nav, setNav] = useState(false);
// nav = false
function handleNav() {
setNav(!nav);
}
return (
<nav className="flex justify-between items-center bg-[#FDECA9] py-3">
<div className="mx-auto mr-25">
<a href="/">
<div className="flex space-x-1 tracking-[4px] text-xl font-semibold items-center">
<span>PLATE</span>
<img
src={require("./images/plate.png")}
className="h-9"
alt="PlateMate Logo"
/>
<span>MATE</span>
</div>
</a>
</div>
<div className="hidden md:flex items-center">
<button
type="button"
className="bg-[#BB5855] mx-0 rounded text-[#FDECA9] text-sm py-1 px-4 relative inline-flex group items-center justify-center cursor-pointer"
data-bs-toggle="modal"
data-bs-target="#signup"
>
<span className="absolute w-0 h-0 transition-all duration-300 ease-out bg-white rounded-full group-hover:w-32 group-hover:h-32 opacity-10"></span>
SIGNUP
</button>
<button
type="button"
className="text-[#BB5855] mx-6 rounded text-sm outline outline-offset-4 outline-2 py-0 px-4 relative font-semibold text-center no-underline transition-all duration-300 ease-in-out cursor-pointer hover:text-[#bb58557c] "
data-bs-toggle="modal"
data-bs-target="#login"
>
LOGIN
</button>
</div>
<div className="block md:hidden">
{/* Mobile Hamburger Icon */}
<button
onClick={handleNav}
className="inline-flex items-center p-2 ml-3 text-sm md:hidden "
>
<img src={require("../src/images/hamburger.png")} width="30px" />
</button>
{/* Dropdown menu */}
<div
className={
nav
? "block absolute right-0 z-10 mt-0 w-56 mr-2 origin-top-right rounded-md bg-[#BB5855] shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
: "hidden"
}
>
<ul className="py-1 text-sm text-gray-100 divide-y ">
<div>
<a
data-bs-toggle="modal"
data-bs-target="#signup"
className="block px-4 py-2 transition-all duration-300 ease-in-out cursor-pointer hover:text-black"
>
SIGNUP
</a>
</div>
<div>
<a
data-bs-toggle="modal"
data-bs-target="#login"
className="block px-4 py-2 transition-all duration-300 ease-in-out cursor-pointer hover:text-black"
>
LOGIN
</a>
</div>
</ul>
</div>
</div>
</nav>
);
}
export default Nav;
I tried researching everything online but I can't find anything with Tailwind, only Bootstrap. I'm expecting the modal to not dismiss when there is an error message but dismiss completely after signed up. It does that but my issue is the grey background not disappearing. I have nothing in my CSS files that would tie to it. I've also tried commenting everything out on all of my files to see if anything was triggering it, however, it still appears. Please help!
Your code shows that you aren't really using React in the way it's intended. You should me managing the state in React, and not manipulating the DOM manually.
A common pattern for removing a modal is to use a state variable to handle the visibility of the component.
const [modalOpen, setModalOpen] = useState(false);
Then around your modal, you can render it conditionally:
return (<>
{modalOpen && (<YourModelHere />)}
</>)
You can then hide/show your modal using the setModalOpen() method.

How do I use a Navbar to search through Data from in Array and match the search in In Nextjs TypeScript?

type Props = {
topic?: string;
}
function Header({topic}: Props) {
const [istopic, setTopic] = useState("");
const{loading, data, error} = !topic? useQuery(GET_POSTS): useQuery(GET_POSTS_BY_TOPIC,{
variables:{
topic:topic,
}
});
const posts: Post[\] = !topic ? data?.getPostList : data?.getPostListByTopic
//HERE IS THE METHOD I USED TO CREATE AN ARRAY FROM THE QUERY LIST
//HERE IS THE FORM INSIDE OF MY NAVBAR THAT I WANT TO USE TO SEARCH THE RESULTS
<form
onSubmit={handleSubmit}
className="flex flex-1 items-center basis-1/3 space-x-2 rounded-md border-none border-gray-500 px-3 py-1"
>
<input
value={istopic}
onChange={(e) => setTopic(e.target.value)}
type="text"
placeholder="Search"
onSubmit={handleSubmit}
className="flex-1 rounded-md border-gray-400 bg-transparent outline-none "
/>
<SearchIcon className="h-7 w-7 text-gray-400" />
<button disabled={!istopic} type="submit" hidden />
</form>;
{
posts ? (
posts
?.filter((post: any) => post.title.match(new RegExp(istopic, "i")))
?.map((post: any) => {
<div>
<a
href={`/channel/${post.channels[0]?.topic}`}
className=" absolute top-6 z-99 bg-blue-600 block py-2 pl-3 pr-4 text-gray-700 rounded"
aria-current="page"
>
{post.title}
</a>
</div>;
console.log(post.title);
})
) : (
<li>
<a
href="#"
className=" absolute top-6 z-99 bg-blue-600 block py-2 pl-3 pr-4 text-gray-700 rounded hover:bg-gray-100"
aria-current="page"
>
Nothing Found
</a>
</li>
);
}
I want to use the data from the array the to check if there is any that matches from the input field and display those matches

Pass selected component to next step of form react

I have a multi step form, which is a quiz. I already set up the context to be able to pass data.
import { useState, createContext, useContext } from "react";
export const QuizContext = createContext();
export default function QuizProvider({ children }) {
const [data, setData] = useState({});
const setQuizValues = (values) => {
setData((prevValues) => ({
...prevValues,
...values,
}));
};
return (
<QuizContext.Provider value={{ data, setQuizValues }}>
{children}
</QuizContext.Provider>
);
}
export const useQuizData = () => useContext(QuizContext);
So, my first step is selecting a card.
The code below:
import { Card } from "../../stories/Card";
import { useQuizData } from "../../context/index"
import { useState } from "react";
const tacos = [
{
cathegory: 'Meat',
imgURL: 'https://images.unsplash.com/photo-1560781290-7dc94c0f8f4f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3024&q=80'
},
{
cathegory: 'Fish',
imgURL: 'https://images.unsplash.com/photo-1510130387422-82bed34b37e9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=975&q=80'
},
{
cathegory: 'Veggi',
imgURL: 'https://images.unsplash.com/photo-1572527129705-a6c197003d61?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=975&q=80'
},
]
export const TacoCathegories = ({quizStep, prevQuizStep, nextQuizStep}) => {
// const { setQuizValues } = useQuizData();
const [isSelected, setisSelected] = useState();
const handleSubmit = (values) => {
setQuizValues(values);
prevQuizStep();
nextQuizStep();
};
return (
<div className={quizStep === 0 ? 'block': 'hidden'}>
<div className="text-center">
<h2 className="text-3xl font-extrabold tracking-tight text-gray-600 sm:text-4xl">What is your favourite taco group?</h2>
</div>
<div className="max-w-7xl mx-auto py-24 px-4 sm:px-6 lg:px-8">
<div className="mt space-y-12 lg:space-y-0 lg:grid lg:grid-cols-3 lg:gap-x-8">
{tacos.map((taco, index) => (
<Card
role="button"
key={index}
title={taco.cathegory}
source={taco.imgURL}
text={`image of ${taco.cathegory} `}
selected={isSelected === index}
onChange={() => setisSelected(index)}
/>
))}
</div>
{tacos[isSelected] && <p>{tacos[isSelected].cathegory}</p>}
<div className="mt-5 sm:mt-8 sm:flex sm:justify-center lg:justify-center">
<div className="rounded-md shadow">
<a role="button" tabIndex={0}
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-gray-200 hover:bg-gray-200 focus:outline-none md:py-4 md:text-lg md:px-10 cursor-not-allowed"
>
Back
</a>
</div>
<div className="mt-3 sm:mt-0 sm:ml-3">
<a
onClick={nextQuizStep}
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-yellow-500 hover:bg-yallow-600 md:py-4 md:text-lg md:px-10"
>
Next
</a>
</div>
</div>
</div>
</div>
);
}
I am able to get the category of selected card tacos[isSelected].cathegory. Depending on the category I need to render different content in Step 2 of my multistep form. Basically, if I choose Meat I will render cards with Meat Tacos, If I choose Fish - with Fish Tacos. For now second step is empty, because I couldn't figure out how to pass selected category to second step.
export const TacoTypes = ({quizStep, prevQuizStep, nextQuizStep}) => {
return (
<div className={quizStep === 1 ? 'block' : 'hidden'}>
<div>
<p>Taco Types are: all you find in the object</p>
</div>
<div className="mt-5 sm:mt-8 sm:flex sm:justify-center lg:justify-center">
<div className="rounded-md shadow">
<a role="button" tabIndex={0}
onClick={prevQuizStep}
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-yellow-500 hover:bg-yallow-600 md:py-4 md:text-lg md:px-10"
>
Back
</a>
</div>
<div className="mt-3 sm:mt-0 sm:ml-3">
<a
onClick={nextQuizStep}
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-yellow-500 hover:bg-yallow-600 md:py-4 md:text-lg md:px-10"
>
Next
</a>
</div>
</div>
</div>
)
}
I am new to react, so any tipp would be helpful!
Sandbox: https://codesandbox.io/s/agitated-euler-pny5n

React send state after login to other component to change html

I'm working on a project ( symfony API ) and ReactJs front-end,
I have a login page which is connected to the api when i get the 201 http response i redirect the user to '/' and set the token in the localstorage but i have an issue in my navbar i have 2 buttons 1 login and the other is for register to redirect to both pages.
When i log in i want to dynamically change the header to a dropdown with user informations and links to user settings etc ... Do you have any ideas ?
Here is the code of Navbar component :
import React, {useEffect, useState} from 'react';
import Dropdown from "./Dropdown";
import {Link} from "react-router-dom";
const Navbar = () => {
const [isloggedin, setIsloggedin] = useState(false);
useEffect(() => {
if (!localStorage.getItem('auth')) {
setIsloggedin(false);
} else {
setIsloggedin(true);
}
}, [])
const ToggleMobileMenu = () => {
const mobile_menu = document.getElementById('mobile-menu')
if (mobile_menu.classList.contains('mobile-hidden')){
mobile_menu.classList.remove('mobile-hidden')
} else {
mobile_menu.classList.add('mobile-hidden')
}
}
return (
<nav className="bg-gray-800 w-full p-4">
<div className="max-w-7xl mx-auto px-2 sm:px-6 lg:px-8">
<div className="relative flex items-center justify-between h-16">
<div className="absolute inset-y-0 left-0 flex items-center sm:hidden">
<button type="button"
className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
aria-controls="mobile-menu" aria-expanded="false"
onClick={ToggleMobileMenu}
>
<span className="sr-only">Open main menu</span>
<svg className="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2"
d="M4 6h16M4 12h16M4 18h16"/>
</svg>
<svg className="hidden h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2"
d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<div className="flex-1 flex items-center justify-center sm:items-stretch sm:justify-start">
<div className="flex-shrink-0 flex items-center">
<Link to={'/'}><img src={'./assets/logo.png'} width={'150'} alt={''}/></Link>
</div>
<div className="hidden sm:flex items-center sm:ml-6 flex">
<div className="flex space-x-4 items-center">
<Link to={'/'}
className="bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium"
aria-current="page">Accueil</Link>
<Link to={'/products'}
className="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Nos
Produits
</Link>
<Link to={'/delivery'}
className="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Livraison</Link>
<Link to={'/contact'}
className="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Contact</Link>
</div>
</div>
</div>
<div
className="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
<div className={'ml-3 relative'}>
{isloggedin ? (
<div className={'ml-3 relative'}>
<Dropdown/>
</div>
) : (
<div className={'ml-3 relative flex'}>
<Link to={'/login'}
className={'hidden md:flex mr-5 text-white bg-red-200 p-3 rounded'}>Se
connecter</Link>
<Link to={'/register'}
className={'hidden md:flex mr-5 text-white bg-red-200 p-3 rounded'}>S'inscrire</Link>
</div>
)}
</div>
</div>
</div>
</div>
<div className="sm:hidden mobile-hidden" id="mobile-menu">
<div className="px-2 pt-2 pb-3 space-y-1">
<Link to={'/'}
className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Accueil</Link>
<Link to={'/products'}
className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Nos Produits</Link>
<Link to={'/delivery'}
className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Livraison</Link>
<Link to={'/contact'}
className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Contact</Link>
{isloggedin ? (
<Link to={'/account'}
className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Mon compte</Link>
) : (
<div>
<Link to={'/login'}
className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Login</Link>
<Link to={'/register'}
className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Register</Link>
</div>
)}
</div>
</div>
</nav>
)
}
export default Navbar;
And here is the Login component :
import React, {useState} from "react";
import { useHistory } from 'react-router-dom';
import axios from "axios";
const Login = () => {
let history = useHistory()
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [success, setSuccess] = useState('');
const LoginHandler = () => {
axios.post('http://127.0.0.1:8000/api/login', {
'username': username,
'password': password
})
.then((r) => {
console.log(r)
setError('')
setSuccess('Vous etes connecté')
setTimeout(() => {
localStorage.setItem('auth', r.data.token)
history.push('/', {auth: true})
}, 3000)
}).catch((error) => {
setError("Username ou mot de passe éroné");
})
}
return (
<div>
<div className={'text-center font-semibold mt-2'}>
{error ? (<p className={'text-red-500'}>{error}</p>) : ( '' )}
{success ? (<p className={'text-green-500'}>{success}</p>) : ( '' )}
</div>
<div className="divide-y divide-gray-200">
<div className="py-8 text-base leading-6 space-y-4 text-gray-700 sm:text-lg sm:leading-7">
<div className="relative">
<input autoComplete="off" id="username" name="username" type="text"
className="peer placeholder-transparent h-10 w-full border-b-2 border-gray-300 text-gray-900 focus:outline-none focus:borer-rose-600"
placeholder="Username"
onChange={(e) => setUsername(e.target.value)}
/>
<label htmlFor="username"
className="absolute left-0 -top-3.5 text-gray-600 text-sm peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-440 peer-placeholder-shown:top-2 transition-all peer-focus:-top-3.5 peer-focus:text-gray-600 peer-focus:text-sm">username</label>
</div>
<div className="relative">
<input autoComplete="off" id="password" name="password" type="password"
className="peer placeholder-transparent h-10 w-full border-b-2 border-gray-300 text-gray-900 focus:outline-none focus:borer-rose-600"
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
/>
<label htmlFor="password"
className="absolute left-0 -top-3.5 text-gray-600 text-sm peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-440 peer-placeholder-shown:top-2 transition-all peer-focus:-top-3.5 peer-focus:text-gray-600 peer-focus:text-sm">Password</label>
</div>
<div className="flex justify-center pt-6">
<button onClick={LoginHandler} className="bg-blue-500 text-white rounded-md px-2 py-1">Se
connecter
</button>
</div>
</div>
</div>
</div>
)
}
export default Login;
Right now your useEffect hook:
useEffect(() => {
if (!localStorage.getItem('auth')) {
setIsloggedin(false);
} else {
setIsloggedin(true);
}
}, [])
... is only triggered on the initial render of the navbar.
You have two options - I'd strongly advice to use the second one.
Option 1: The useEffect Hook has a dependency list (the second parameter passed to useEffect. Whenever any value inside that dependency list changes, the code is run again. So in order for the navbar to update, you have to add that localStorage "state" to the list. However, I don't know whether this will work that well - this is not the "react way" of doing things.
Option 2: Change your State Hierarchy. Right now your hierarchy looks like this:
<Navbar>
<Login>
</Navbar>
In react you should store state with useState (you can add auth to the localStorage in addition to that). That state should be stored in the highest order component that is affected by the state.
Solution: useState for a user object inside Navbar. Pass the setUserState function to the login component and trigger setUserState on successful login (next to localStorage.setItem). Add that userState to the dependency list of the useEffect hook mentioned above.

Resources