I need to update my component after user set like, what methods should I use for this? I m newbie in react-redux and even dont know some basics things.
I also have redux-thunk in my project but im even don`t know how to use it for async responses.
PostCard code.
import * as React from "react";
//Redux
import { useDispatch } from "react-redux";
import { likePostById } from "../Redux/Slice/PostSlice";
import { GetPostByInterests } from "../Redux/Slice/PostSlice";
export const PostCard = (props) => {
const posts = props.posts;
const dispatch = useDispatch();
const LikePost = (id, is_user_liked) => {
const is_liked = !is_user_liked;
dispatch(likePostById(id, is_liked))
}
return (
<div className="flex bg-white shadow-lg rounded-lg mx-4 md:mx-auto max-w-md md:max-w-2xl mt-2">
<div className="flex items-start px-4 py-6">
<img
className="w-12 h-12 rounded-full object-cover mr-4 shadow"
src={posts?.author.avatar.url}
alt="avatar"
></img>
<div className="">
<div className="flex items-center justify-between">
<h2 className="text-lg font-semibold text-gray-900 -mt-1">
{posts.author.first_name} {posts.author.last_name}
</h2>
<small className="text-sm text-gray-700">{}</small>
</div>
<p className="mt-3 text-gray-700 text-sm">{posts.text}</p>
<div className="mt-4 flex items-center">
<div className="flex mr-2 text-gray-700 text-sm mr-3">
{posts.is_user_liked ? (
<svg
fill="#f01616"
viewBox="0 0 24 24"
className="w-4 h-4 mr-1"
stroke="currentColor"
onClick={() => {LikePost(posts.id, posts.is_user_liked)}}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
/>
</svg>
) : (
<svg
fill="none"
viewBox="0 0 24 24"
className="w-4 h-4 mr-1"
stroke="currentColor"
onClick={() => {LikePost(posts.id, posts.is_user_liked)}}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
/>
</svg>
)}
<span>{posts.likes_count}</span>
</div>
<div className="flex mr-2 text-gray-700 text-sm mr-8">
<svg
fill="none"
viewBox="0 0 24 24"
className="w-4 h-4 mr-1"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z"
/>
</svg>
<span>{posts.comments_count}</span>
</div>
</div>
</div>
</div>
</div>
);
};
export default PostCard;
Redux PostSlice
Server Post answer
id(pin): 143
text(pin): "some text"
topic(pin): "ANDROID_DEVELOPMENT"
publish_time(pin): "2022-06-02T23:28:18.415933"
is_user_liked(pin): true
likes_count(pin): 2
comments_count(pin): 0
const initialState = {
posts: [],
};
const post = createSlice({
name: "post",
initialState,
reducers: {
getPosts(state, action) {
state.posts = action.payload.posts;
},
likePost(state, action){
state.posts.is_user_liked = action.payload.is_user_liked;
},
},
});
const { likePost } = post.actions;
export function likePostById(id, is_liked) {
return async (dispatch) => {
try {
await API.post("/posts/" + id + "/like", null, {
params: {
is_liked: is_liked,
},
});
dispatch(
likePost({
is_user_liked: !is_liked,
})
)
} catch (e) {
console.log(e);
}
};
}
Related
I want an effect like this (before onclick)(after oncilck).Just click on which div to make it disappear, and then let the div that disappeared before show again.
Here is the data code(just an array). I want the "show" variable in the data to control whether to display.But I don't know how to implement the destructuring assignment to the array in the click function.
Thank you for your answer!
const leftBarData=
[{
name:"关于音乐",
color:"bg-music-color",
icon:<div className="iconMusicSize">
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
blahblah
</svg>
</div>,
link:"/music",
number:0,
show:true,
},
{
name:"关于编程",
color:"bg-code-color",
icon:<div className="iconSize">
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
blah
</svg>
</div>,
link:"/code",
number:1,
show:true,
},
{
name:"关于设计",
color:"bg-design-color",
icon:<div className="iconSize">
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
blah
</svg>
</div>,
link:"/design",
number:2,
show:false
},
{
name:"关于本人",
color:"bg-about-color",
icon:<div className="iconSize">
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
blah
</svg>
</div>,
link:"/design",
number:3,
show:true
}
]
Here is the map.
const [statusData,setStatusData]=useState(leftBarData)
const changeBar=(pars)=>
{
how to achieve it
}
<div className="flex fixed">
{statusData?.map((index,i)=>(
<Link to={index.link}>
<div className={` ${index.color} ${index.show?"":"hidden"} w-99 h-screen pt-9 `} onClick={()=>changeBar(index)}>
<div className="flex flex-col h-full items-center justify-between">
{index.icon}
<div className="-rotate-90 -translate-y-full mb-10">
<div className="h3 text-white whitespace-nowrap">{index.name}</div>
</div>
</div>
</div>
</Link>
))}
</div>
You can map() your state data to toggle show property of clicked element like this:
const changeBar = pars => {
setStatusData(data => data.map(item => (
item === pars
? {
...item,
show: !item.show
}
: item
)));
};
Using Map method to with function to Set State to Change url of video. So whenever i click on any video from list it change the state hence my videos are change in Player .
The problem is that i want to have two button next and Previous to Show previous & next video, i dont have any idea how to do that Here is My Code
// import React from "react";
import React, { useState } from "react";
import ReactPlayer from "react-player";
const List = [
{
title: "The Shawshank Redemption",
innerList: [
{
innertitle: "1 Two imprisoned",
describe:"1 Client has methods for creating new data and offers a type-safe way to do it. In this lesson, we take a look at how to add new records in our database by hitting an API routeRehan1",
url: "https://res.cloudinary.com/netdesignr-ltd/video/upload/v1662112952/How%20to%20smart%20money%20concepts/videoplayback_2_uoihtg.mp4",
poster:
"https://m.media-amazon.com/images/M/MV5BODU4MjU4NjIwNl5BMl5BanBnXkFtZTgwMDU2MjEyMDE#._V1_.jpg",
time: "2m",
},
{
innertitle: "2 Two imprisoned",
describe:"2 Client has methods for creating new data and offers a type-safe way to do it. In this lesson, we take a look at how to add new records in our database by hitting an API routeRehan1",
url: "https://res.cloudinary.com/netdesignr-ltd/video/upload/v1662099142/How%20to%20smart%20money%20concepts/videoplayback_dvjulu.mp4",
poster:
"https://m.media-amazon.com/images/M/MV5BODU4MjU4NjIwNl5BMl5BanBnXkFtZTgwMDU2MjEyMDE#._V1_.jpg",
time: "2h 22m",
},
{
innertitle: "3 Two imprisoned",
describe:"3 Client has methods for creating new data and offers a type-safe way to do it. In this lesson, we take a look at how to add new records in our database by hitting an API routeRehan1",
url: "https://res.cloudinary.com/netdesignr-ltd/video/upload/v1662112893/How%20to%20smart%20money%20concepts/videoplayback_aw5zoh.mp4",
poster:
"https://m.media-amazon.com/images/M/MV5BODU4MjU4NjIwNl5BMl5BanBnXkFtZTgwMDU2MjEyMDE#._V1_.jpg",
time: "2h 22m",
},
],
},
{
title: "The Shawshank Redemption",
innerList: [
{
innertitle: "1 Two imprisoned",
describe:"1 Client has methods for creating new data and offers a type-safe way to do it. In this lesson, we take a look at how to add new records in our database by hitting an API routeRehan1",
url: "https://res.cloudinary.com/netdesignr-ltd/video/upload/v1662112952/How%20to%20smart%20money%20concepts/videoplayback_2_uoihtg.mp4",
poster:
"https://m.media-amazon.com/images/M/MV5BODU4MjU4NjIwNl5BMl5BanBnXkFtZTgwMDU2MjEyMDE#._V1_.jpg",
time: "2h 22m",
},
{
innertitle: "2 Two imprisoned",
describe:"2 Client has methods for creating new data and offers a type-safe way to do it. In this lesson, we take a look at how to add new records in our database by hitting an API routeRehan1",
url: "https://res.cloudinary.com/netdesignr-ltd/video/upload/v1662099142/How%20to%20smart%20money%20concepts/videoplayback_dvjulu.mp4",
poster:
"https://m.media-amazon.com/images/M/MV5BODU4MjU4NjIwNl5BMl5BanBnXkFtZTgwMDU2MjEyMDE#._V1_.jpg",
time: "2h 22m",
},
{
innertitle: "3 Two imprisoned",
describe:"3 Client has methods for creating new data and offers a type-safe way to do it. In this lesson, we take a look at how to add new records in our database by hitting an API routeRehan1",
url: "https://res.cloudinary.com/netdesignr-ltd/video/upload/v1662112893/How%20to%20smart%20money%20concepts/videoplayback_aw5zoh.mp4",
poster:
"https://m.media-amazon.com/images/M/MV5BODU4MjU4NjIwNl5BMl5BanBnXkFtZTgwMDU2MjEyMDE#._V1_.jpg",
time: "2h 22m",
},
],
},
{
title: "The Shawshank Redemption",
innerList: [
{
innertitle: "1 Two imprisoned",
describe:"1 Client has methods for creating new data and offers a type-safe way to do it. In this lesson, we take a look at how to add new records in our database by hitting an API routeRehan1",
url: "https://res.cloudinary.com/netdesignr-ltd/video/upload/v1662112952/How%20to%20smart%20money%20concepts/videoplayback_2_uoihtg.mp4",
poster:
"https://m.media-amazon.com/images/M/MV5BODU4MjU4NjIwNl5BMl5BanBnXkFtZTgwMDU2MjEyMDE#._V1_.jpg",
time: "2h 22m",
},
{
innertitle: "2 Two imprisoned",
describe:"2 Client has methods for creating new data and offers a type-safe way to do it. In this lesson, we take a look at how to add new records in our database by hitting an API routeRehan1",
url: "https://res.cloudinary.com/netdesignr-ltd/video/upload/v1662099142/How%20to%20smart%20money%20concepts/videoplayback_dvjulu.mp4",
poster:
"https://m.media-amazon.com/images/M/MV5BODU4MjU4NjIwNl5BMl5BanBnXkFtZTgwMDU2MjEyMDE#._V1_.jpg",
time: "2h 22m",
},
{
innertitle: "3 Two imprisoned",
describe:"3 Client has methods for creating new data and offers a type-safe way to do it. In this lesson, we take a look at how to add new records in our database by hitting an API routeRehan1",
url: "https://res.cloudinary.com/netdesignr-ltd/video/upload/v1662112893/How%20to%20smart%20money%20concepts/videoplayback_aw5zoh.mp4",
poster:
"https://m.media-amazon.com/images/M/MV5BODU4MjU4NjIwNl5BMl5BanBnXkFtZTgwMDU2MjEyMDE#._V1_.jpg",
time: "2h 22m",
},
],
},
];
// when click on previous button show previous video
export function WatchList() {
const [previos, setPrevios] = useState(false);
const [list, setList] = React.useState({
title: "The Shawshank Redemption",
innerTitle: "Two imprisoned",
describe:"Client has methods for creating new data and offers a type-safe way to do it. In this lesson, we take a look at how to add new records in our database by hitting an API routeRehan1",
url: "https://www.youtube.com/watch?v=6hB3S9bIaco",
time: "2h 22m",
});
const handleVideoData = (data: any,index:any) => {
setList(data);
};
const previousVideo = () => {
}
return (
<div className="mx-auto w-full bg-smart-60 p-2">
<div className="mx-auto flex flex-col md:flex-row">
<div className="p-8 md:grid-cols-3">
<div className="h-96 w-full overflow-auto bg-smart-50 px-4 md:h-screen md:w-[320px] ">
<div>
<div className="mt-5 flex justify-center">
<img src="/logo.webp" alt="logo" width={200} height={200} />
</div>
<div className="-m-4 mb-4 border-b border-blue-900 px-4 py-6"></div>
</div>
{List.map((data, i) => (
<div className="mb-6" key={i}>
<div className="p-2">
<p className="font-semibold tracking-wider text-smart-70">
{data.title}
</p>
</div>
{data.innerList.map((data, i) => (
<ul key={i}>
<button
className="w-full"
onClick={() => {
handleVideoData(data,i);
}}
>
<li className="group mb-2 rounded-lg border border-transparent bg-gradient-to-br from-transparent to-transparent px-2 py-3 transition duration-200 ease-in-out hover:from-blue-500 hover:to-blue-900">
<div className="flex">
<img
className="m-auto mr-4 w-24 rounded-md"
src="/thumbnail.webp"
alt="imageslist"
/>
<div className="w-full text-left">
<div className="">
<p className="mr-2 text-smart-70">
{data.innertitle}
</p>
</div>
<p className="inline-block text-sm text-gray-500 group-hover:text-gray-300">
{data.time}
</p>
</div>
</div>
</li>
</button>
</ul>
))}
</div>
))}
</div>
</div>
<div className="grid md:grid-cols-9 ">
<div className="col-span-12 lg:col-span-9">
<section className="sticky top-0 mb-6">
<nav className="bg-mid-deep flex flex-col justify-between rounded-xl bg-opacity-30 px-6 py-4 text-gray-200 md:flex-row">
<section className="my-auto">
<h1>
<span className="font-semibold text-gray-200">
{list.title}
</span>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
className="inline-block w-5"
>
<path
fillRule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clipRule="evenodd"
></path>
</svg>
<span className="text-gray-400">
{list.innerTitle}
</span>
</h1>
</section>
<section className="mt-2 flex w-full md:mt-0 md:justify-end xl:w-1/3">
<button className="mr-2 flex flex-row rounded-xl border border-blue-900 px-4 py-2 text-left text-xs text-gray-200 hover:text-blue-300 sm:text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
className="my-auto mr-2 inline-block w-4"
>
<path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z"></path>
<path
fillRule="evenodd"
d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3zm-3 4a1 1 0 100 2h.01a1 1 0 100-2H7zm3 0a1 1 0 100 2h3a1 1 0 100-2h-3z"
clipRule="evenodd"
></path>
</svg>
<span className="my-auto">Show Transcripts</span>
</button>
<button className="flex rounded-xl border border-blue-900 px-4 py-2 text-sm text-gray-200 hover:text-blue-300">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
aria-hidden="true"
className="my-auto mr-2 inline-block w-4"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
></path>
</svg>
<span className="my-auto">Log in</span>
</button>
</section>
</nav>
</section>
<div className="sticky top-20 grid grid-cols-9 gap-6">
<section className="col-span-9">
<div className="sticky top-20">
<section className="w-full rounded-xl">
<section className="flex">
<ReactPlayer
url={list.url}
controls={true}
width="100%"
height="600px"
/>
</section>
<section className="flex justify-between bg-smart-50 px-4 py-8">
<div className="rounded-md ">
<p className="text-xl text-white sm:text-3xl">
{list.innerTitle}
</p>
<p className="mt-1 text-gray-500">{list.time}</p>
<div className="mt-4">
<p className="text-sm text-gray-400 sm:text-lg">
{list.describe}
</p>
</div>
</div>
<div className="my-auto flex ">
<button>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
aria-hidden="true"
className="mr-2 inline-block w-8 cursor-pointer text-gray-400 hover:text-red-400"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
></path>
</svg>
</button>
<span className="my-auto text-sm text-gray-400">0</span>
</div>
</section>
</section>
<section className="mt-4 rounded-md bg-smart-50">
<section className="bg-mid-deep flex justify-between rounded-xl bg-opacity-30 px-6 py-4">
<button onClick={() => previousVideo()} className="rounded-xl border border-blue-500 px-4 py-2 text-sm text-gray-200 hover:text-blue-300">
← Previous
</button>
<button className="rounded-xl border border-blue-500 px-4 py-2 text-sm text-gray-200 hover:text-blue-300">
Next →
</button>
</section>
</section>
</div>
</section>
</div>
</div>
</div>
</div>
</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I think this task can be accomplished using a simple index:
const [index, setIndex] = useState(0);
const previousVideo = () => {
const newIndex = index > 0 ? index - 1 : 0;
setIndex(newIndex);
setList(List[index]);
};
Of course, you will have to adapt the data from List to the one in list, but that should be easy.
I'm a React newbie, came across an interesting challenge to create "fake ecommerce page" with this api.
My Products.js file is this. I get api response and save it to a state(console logging it in one line to make sure it's working). You click on a SVG icon of + sign and that item gets "added" to the cart(don't want to add whole item for now, but just make it seems like it's adding it with setCartItems(cartItems + 1) so only number increases). Only thing is that the cart icon is in Header.js component, and I need to pass it there somehow. I've tried with props but couldn't get it to work.
Any help is very much appreciated since I want to learn from your code.
import React from 'react'
import {useState, useEffect} from 'react'
import axios from 'axios'
import plus from '../images/plus.svg'
export default function Products(props) {
const [products, setProducts] = useState([])
const [cartItems, setCartItems] = useState(0)
const updateCart = () => {
setCartItems(cartItems + 1)
console.log(cartItems)
}
useEffect(() => {
axios({
method: 'GET',
url: 'https://api.escuelajs.co/api/v1/products'
}).then((response) => {
setProducts(response.data)
console.log(response.data)
})
}, [])
return (
<section className="bg-white py-8">
<div className="container mx-auto flex items-center flex-wrap pt-4 pb-12">
<nav id="store" className="w-full z-30 top-0 px-6 py-1">
<div
className="w-full container mx-auto flex flex-wrap items-center justify-between mt-0 px-2 py-3">
<a className="uppercase tracking-wide no-underline hover:no-underline font-bold text-gray-800 text-xl "
href="#">
Store
</a>
<div className="flex items-center" id="store-nav-content">
<a className="pl-3 inline-block no-underline hover:text-black" href="#">
<svg className="fill-current hover:text-black" xmlns="http://www.w3.org/2000/svg"
width="24" height="24" viewBox="0 0 24 24">
<path d="M7 11H17V13H7zM4 7H20V9H4zM10 15H14V17H10z"></path>
</svg>
</a>
<a className="pl-3 inline-block no-underline hover:text-black" href="#">
<svg className="fill-current hover:text-black" xmlns="http://www.w3.org/2000/svg"
width="24" height="24" viewBox="0 0 24 24">
<path
d="M10,18c1.846,0,3.543-0.635,4.897-1.688l4.396,4.396l1.414-1.414l-4.396-4.396C17.365,13.543,18,11.846,18,10 c0-4.411-3.589-8-8-8s-8,3.589-8,8S5.589,18,10,18z M10,4c3.309,0,6,2.691,6,6s-2.691,6-6,6s-6-2.691-6-6S6.691,4,10,4z"></path>
</svg>
</a>
</div>
</div>
</nav>
{
products.slice(0, 20).map((product) => {
return (
<div className="w-full md:w-1/3 xl:w-1/4 p-6 flex flex-col" key={product.id}>
<div>
<img className="hover:grow hover:shadow-lg" src={product.category.image}
alt={product.description}/>
<div className="pt-3 flex items-center justify-between">
<p className="uppercase font-bold text-lg">{product.title}</p>
<img src={plus} width='20px' onClick={updateCart} alt={product.description}/>
</div>
<p className="pt-1 text-left text-gray-900">{product.price} €</p>
</div>
</div>
)
}
)
}
</div>
</section>
)
}
This is my Header.js file.
import React from 'react'
export default function Header() {
return (
<nav id="header" className="w-full z-30 top-0 py-1">
<div className="w-full container mx-auto flex flex-wrap items-center justify-between mt-0 px-6 py-3">
<label className="cursor-pointer md:hidden block">
<svg className="fill-current text-gray-900" xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 20 20">
<title>menu</title>
<path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"></path>
</svg>
</label>
<input className="hidden" type="checkbox" id="menu-toggle" />
<div className="hidden md:flex md:items-center md:w-auto w-full order-3 md:order-1" id="menu">
<nav>
<ul className="md:flex items-center justify-between text-base text-gray-700 pt-4 md:pt-0">
<li><a className="inline-block no-underline hover:text-black hover:underline py-2 px-4" href="#">Shop</a></li>
<li><a className="inline-block no-underline hover:text-black hover:underline py-2 px-4" href="#">About</a></li>
</ul>
</nav>
</div>
<div className="order-1 md:order-2">
<a className="flex items-center tracking-wide no-underline hover:no-underline font-bold text-gray-800 text-xl " href="#">
<svg className="fill-current text-gray-800 mr-2" xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 24 24">
<path d="M5,22h14c1.103,0,2-0.897,2-2V9c0-0.553-0.447-1-1-1h-3V7c0-2.757-2.243-5-5-5S7,4.243,7,7v1H4C3.447,8,3,8.447,3,9v11 C3,21.103,3.897,22,5,22z M9,7c0-1.654,1.346-3,3-3s3,1.346,3,3v1H9V7z M5,10h2v2h2v-2h6v2h2v-2h2l0.002,10H5V10z"></path>
</svg>
NORDICS
</a>
</div>
<div className="order-2 md:order-3 flex items-center" id="nav-content">
<a className="inline-block no-underline hover:text-black" href="#">
<svg className="fill-current hover:text-black" xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 24 24">
<circle fill="none" cx="12" cy="7" r="3"></circle>
<path d="M12 2C9.243 2 7 4.243 7 7s2.243 5 5 5 5-2.243 5-5S14.757 2 12 2zM12 10c-1.654 0-3-1.346-3-3s1.346-3 3-3 3 1.346 3 3S13.654 10 12 10zM21 21v-1c0-3.859-3.141-7-7-7h-4c-3.86 0-7 3.141-7 7v1h2v-1c0-2.757 2.243-5 5-5h4c2.757 0 5 2.243 5 5v1H21z"></path>
</svg>
</a>
<a className="pl-3 inline-block no-underline hover:text-black" href="#">
<svg className="fill-current hover:text-black" xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 24 24">
<path d="M21,7H7.462L5.91,3.586C5.748,3.229,5.392,3,5,3H2v2h2.356L9.09,15.414C9.252,15.771,9.608,16,10,16h8 c0.4,0,0.762-0.238,0.919-0.606l3-7c0.133-0.309,0.101-0.663-0.084-0.944C21.649,7.169,21.336,7,21,7z M17.341,14h-6.697L8.371,9 h11.112L17.341,14z"></path>
<circle cx="10.5" cy="18.5" r="1.5"></circle>
<circle cx="17.5" cy="18.5" r="1.5"></circle>
</svg>
<div className="inline-flex absolute top-4 justify-center items-center w-5 h-5 text-xs font-bold text-white bg-red-500 rounded-full">NUMBER OF ITEMS IN CART GOES HERE</div>
</a>
</div>
</div>
</nav>
)
}
And finally, if needed, this is my App.js file.
import './App.css';
import About from './components/About';
import Header from './components/Header';
import Hero from './components/Hero';
import Products from './components/Products';
function App() {
return (
<div className="App">
<Header />
<Hero />
<Products />
<About />
</div>
);
}
export default App;
I provide two methods for your refrence:
1.By using props:
just put your state and set function at their father element, in your situation you can put in App.js, then props to any components you want:
App.js
import './App.css';
import About from './components/About';
import Header from './components/Header';
import Hero from './components/Hero';
import Products from './components/Products';
import axios from 'axios'
function App() {
const [products, setProducts] = useState([]) // put here
const [cartItems, setCartItems] = useState(0) // put here
// get your api here
useEffect(() => {
axios({
method: 'GET',
url: 'https://api.escuelajs.co/api/v1/products'
}).then((response) => {
setProducts(response.data)
})
}, [])
return (
<div className="App">
<Header setCartItems={setCartItems} cartItems={cartItems}/>
<Hero />
<Products cartItems={cartItems} setCartItems={setCartItems} products={products} setProducts={setProducts}/>
<About />
</div>
);
}
export default App;
after then in your Products.js and Header.js can get props data, and can get props set feunction to update state.
But I think put global state is better,
I recommend useContext or zustand to do it!
2.Put in zustand:
create file named store.js, then npm install zustand
store.js
import create from 'zustand';
// this is our useStore hook that we can use in our components to get parts of the store and call actions
const useStore = create((set, get) => ({
cartItems: 0,
setCartItems: (value) =>
set((state) => ({
cartItems: value,
})),
}));
export default useStore;
Product.js and Header.js add below code:
import useStore from './store'; // import the store you writed before
export default function Products(props) {
// get your store state and function
const { cartItems, setCartItems } = useStore();
// update your store state
const updateCart = () => {
setCartItems(cartItems + 1)
}
const minusCart = () => {
setCartItems(cartItems - 1)
}
//...your other code
}
You either need to use global state management like redux or pass a callback function from the header to the products component to update the state. React is unidirectional data flow downward, so you can't pass props back up like you can from parent to child.
I am making a side nav for which I need to add the left border to the current tab How can I achieve this using state by passing a boolean value to the Child SideNavItem class as a prop and the change it on every tab change.
Here is My code for the parent SideNav class
Here I am using an if-else condition to check for the current location and the pass that is a prop to the Child class. But Right now both the Home and My Profile is getting the side border.
import { NavLink } from "react-router-dom";
import SideNavItems from "./SideNavItems";
import React, {useState} from 'react';
const HomeIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-8 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
/>
</svg>
);
const ProfileIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-8 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
/>
</svg>
);
const PointIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-8 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z"
/>
</svg>
);
const SupportIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-8 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
/>
</svg>
);
const ContributeIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-8 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
/>
</svg>
);
const SideNav = (): JSX.Element => {
let [active, setActive] = useState(true);
let isActive = (currentPath: any, thisPath: any) => {
if (currentPath===thisPath) {
setActive(true)
} else {
setActive(false);
}
return active;
}
const resetState = () => {
setActive(false);
};
return (
<div className="sidebar mt-5">
<div className="logo ml-2">
<img
alt="logo"
src={require("../assets/images/logo.png").default}
/>
</div>
<NavLink to="/"><SideNavItems active={() => isActive(window.location.pathname, "/")} icon={HomeIcon} text={"Home"}/></NavLink>
<NavLink to="/profile"><SideNavItems active={() => isActive(window.location.pathname, "/profile")} icon={ProfileIcon} text={"My Profile"}/></NavLink>
<SideNavItems active={""} icon={PointIcon} text={"Daily Points"}/>
<SideNavItems active={""} icon={SupportIcon} text={"Support"}/>
<SideNavItems active={""} icon={ContributeIcon} text={"Contribute"}/>
</div>
);
};
export default SideNav;
Here is the code for Child Class
import React from "react";
type Props = {
active: any;
text: string;
icon: any;
};
const SideNavItems: React.FC<Props> = ({active, icon, text }) => (
<div className={`flex items-center cursor-pointer hover:text-red-400 transition duration-100 ease-in-out ${active ? ` text-red-400 border-l-4 border-red-400` : ``}`}>
<div className="icon p-5">{icon}</div>
<h2 className="font-extrabold text-xl mr-5">{text}</h2>
</div>
);
export default SideNavItems;
Part of the confusion you're facing here is due to the fact that calling setActive in the isActive function doesn't immediately change the value of the active variable, and since you are returning the active variable immediately, you are actually returning the previous value active, not the intended value.
In fact, you probably don't need to save the value of active in a component state variable:
const SideNav = (): JSX.Element => {
return (
<div className='sidebar mt-5'>
<div className='logo ml-2'>
<img alt='logo' src={require('../assets/images/logo.png').default} />
</div>
<NavLink to='/'>
<SideNavItems
active={window.location.pathname === '/'}
icon={HomeIcon}
text={'Home'}
/>
</NavLink>
<NavLink to='/profile'>
<SideNavItems
active={window.location.pathname === '/profile'}
icon={ProfileIcon}
text={'My Profile'}
/>
</NavLink>
<SideNavItems active={''} icon={PointIcon} text={'Daily Points'} />
<SideNavItems active={''} icon={SupportIcon} text={'Support'} />
<SideNavItems active={''} icon={ContributeIcon} text={'Contribute'} />
</div>
);
};
export default SideNav;
or if you're using react router, you can use the useLocation hook to make sure the component always re-renders when the path changes:
import { useLocation } from 'react-router-dom';
const SideNav = (): JSX.Element => {
const { pathname: currentPath } = useLocation();
return (
<div className='sidebar mt-5'>
<div className='logo ml-2'>
<img alt='logo' src={require('../assets/images/logo.png').default} />
</div>
<NavLink to='/'>
<SideNavItems
active={currentPath === '/'}
icon={HomeIcon}
text={'Home'}
/>
</NavLink>
<NavLink to='/profile'>
<SideNavItems
active={currentPath === '/profile'}
icon={ProfileIcon}
text={'My Profile'}
/>
</NavLink>
<SideNavItems active={''} icon={PointIcon} text={'Daily Points'} />
<SideNavItems active={''} icon={SupportIcon} text={'Support'} />
<SideNavItems active={''} icon={ContributeIcon} text={'Contribute'} />
</div>
);
};
export default SideNav;
I'm trying to maintain a track of use inputs with react's use state.
for some reason this is quite difficult.
the function i'm using right now is,
function handleClick(e) {
setAnswers([...answers, answer ]);
// setTheArray([, newElement]);
setAnswer()
setTime(true);
setStage(Stage + 1);
e.preventDefault();
console.log("The link was clicked.");
console.log(answers);
}
the input section looks like this,
<div className=" items-center ">
<label for="answer" className="sr-only font-thin px-2 pb-4 text-lg">
Answer
</label>
<input
onChange={(e) => setAnswer(e.target.value)}
type="text"
value={answer}
name="answer"
id="answer"
className=" items-center shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md"
placeholder="Enter Here"
/>
</div>
and the button
<button
onClick={handleClick}
className="bg-blue-500 hover:bg-blue-700shadow-xl font-semibold rounded-full fixed right-8 bottom-20 text-xl px-8 py-3 sm:right-16 sm:bottom-16 text-white sm:text-xl sm:py-3 sm:px-7 flex items-center focus:outline-none"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="-ml-1 mr-2 h-5 w-5"
>
<circle cx="12" cy="12" r="10"></circle>
<polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"></polygon>
</svg>
<span>Submit </span>
</button>
Essentially I want to keep track of the user inputs over time - I could just create a class based component, but i'd rather just use functions if possible.
This is the entire component,
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { requireAuth } from "util/auth.js";
import Sidebar_Users from "components/dashboard/Sidebar/Sidebar_Users";
import MindVaultSection from "components/dashboard/MindVault/MindVaultSection";
import BottomNavigation from "../../components/dashboard/BottomNavigation/BottomNavigation";
/*
This page takes a measurement of someone's working memory,
being how many digits they
are able to remember in a set time period.
To do this there needs to be:
- Digits made randomly,
- Timer,
- Input for user answers based on the progress through the task,
- Record of medication, or lack thereof
Ideally doing 6 tests total - sending data at each point if possible, perhaps just as a total query at end though.
User Flow
- Initial Component
- Component for remembering Text
- Component for entering
- Rest Component
*/
function makeid(length) {
var result = "";
var characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
function ButtonBaseline(props) {
const { time, Colour, handleClick, Stage, onSubmit } = props;
if (time == false)
return (
<button
onClick={handleClick}
className="bg-blue-500 hover:bg-blue-700shadow-xl font-semibold rounded-full fixed right-8 bottom-20 text-xl px-8 py-3 sm:right-16 sm:bottom-16 text-white sm:text-xl sm:py-3 sm:px-7 flex items-center focus:outline-none"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="-ml-1 mr-2 h-5 w-5"
>
<circle cx="12" cy="12" r="10"></circle>
<polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"></polygon>
</svg>
<span>Get Started</span>
</button>
);
else if (time == "input" && Stage < 6)
return (
<button
onClick={handleClick}
className="bg-blue-500 hover:bg-blue-700shadow-xl font-semibold rounded-full fixed right-8 bottom-20 text-xl px-8 py-3 sm:right-16 sm:bottom-16 text-white sm:text-xl sm:py-3 sm:px-7 flex items-center focus:outline-none"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="-ml-1 mr-2 h-5 w-5"
>
<circle cx="12" cy="12" r="10"></circle>
<polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"></polygon>
</svg>
<span>Next Step </span>
</button>
);
else if (time == "input" && Stage == 6)
return (
<button
onClick={handleClick}
className="bg-blue-500 hover:bg-blue-700shadow-xl font-semibold rounded-full fixed right-8 bottom-20 text-xl px-8 py-3 sm:right-16 sm:bottom-16 text-white sm:text-xl sm:py-3 sm:px-7 flex items-center focus:outline-none"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="-ml-1 mr-2 h-5 w-5"
>
<circle cx="12" cy="12" r="10"></circle>
<polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"></polygon>
</svg>
<span>Submit </span>
</button>
);
else
return (
<div className="bg-blue-500 hover:bg-blue-700shadow-xl font-semibold rounded-full fixed right-8 bottom-20 text-xl px-8 py-3 sm:right-16 sm:bottom-16 text-white sm:text-xl sm:py-3 sm:px-7 flex items-center focus:outline-none">
Waiting!
</div>
);
}
function Baseline(props) {
const [Stage, setStage] = useState(0); // walkthrough Status
const [time, setTime] = useState(false); //timer off, on, or in input stage.
const [answer, setAnswer] = useState();
const [answers, setAnswers] = useState([]);
// RandomString generates a random string of length n
var numbers = makeid(0 + 2 * Stage);
//qSLeD9D0PlSE
useEffect(() => {
//this sets the time to wait, being 3 seconds
if (time) {
const timeout = setTimeout(() => {
// do anything, this block runs after the timeout has "expired"
// could even set state
setTime("input");
console.log("The timeout was called.");
}, 3000); // timeout expires in 6000 ms
// make sure to clear the timeout on component unmount to avoid memory loss issues
return () => clearTimeout(timeout);
// this callback function runs only on component unmount, not re-renders
}
}, [time]);
function handleOnChange(e) {
setAnswer(e.target.value);
}
function handleClick(e) {
setAnswers([...answers, answer ]);
// setTheArray([, newElement]);
setAnswer()
setTime(true);
setStage(Stage + 1);
e.preventDefault();
console.log("The link was clicked.");
console.log(answers);
}
let testInput;
if (time == true) {
testInput = (
<>
<div>Stage {Stage}</div>
<div className="underline font-light items-center justify-center">
Hold the numbers in your head!
</div>
<div className="uppercase bg-white tracking-widest text-center font-bold text-5xl shadow p-4 items-center">
{numbers}
</div>
</>
);
} else if (time == "input") {
testInput = (
<>
<div>Stage {Stage}</div>
<div className="font-thin px-2 pb-4 text-lg">Enter Numbers</div>
<div className="bg-white rounded-lg shadow p-4 items-center justify-center">
<div className=" items-center ">
<label for="answer" className="sr-only font-thin px-2 pb-4 text-lg">
Answer
</label>
<input
onChange={handleOnChange}
type="text"
value={answer}
name="answer"
id="answer"
className=" items-center shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md"
placeholder="Enter Here"
/>
</div>
</div>
</>
);
} else if (time == false) {
testInput = (
<>
<p className="text-lg leading-7 text-gray-500 mb-5">
You are about to do a small short term memory test. A few letters will
flash on your computer monitor for 3 seconds. Your job is to write
down as many letters as you can remember
</p>
</>
);
}
return (
<>
<Sidebar_Users dashboard={"Progress Map"}>
<div className="py-8 min-h-full container mx-auto ">
<div className="mt-2 mb-8 text-3xl leading-8 font-extrabold tracking-tight text-gray-900 sm:text-4xl sm:leading-10">
Working Memory Test
</div>
{testInput}
<ButtonBaseline
time={time}
Stage={Stage}
handleClick={handleClick}
// onSubmit={onSubmit}
/>
</div>
</Sidebar_Users>
</>
);
}
export default Baseline;
Cheers!
Here is how you would keep track of all your answers. Since you don't have all your code dealing with stages I can't make this answer more specific
but, if this is not enough letme know where to elaborate.
import React, { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const [answers, setAnswers] = useState([]);
const [answer, setAnswer] = useState("");
const [isSubmit, setIsSubmit] = useState(false);
useEffect(() => {
if (answers.length === 6) {
//here you would fire your submit to server
setIsSubmit(true);
}
}, [answers]);
function handleClick(e) {
if (!isSubmit) setAnswers([...answers, answer]);
}
function handleOnChange(e) {
setAnswer(e.target.value);
}
return (
<div className="App">
<input value={answer} onChange={handleOnChange} />
<button onClick={(e) => handleClick(e)}>Submit</button>
<ul>
{answers.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
{isSubmit ? "Has Submitted" : "Has not Submitted"}
</div>
);
}
Update: Added some stage logic