I am trying to render a list of orders in the your orders page using firebase as a backend and react as a front end. When I click a your order button it shows nothing and when refresh the page it displays the data . I want the data to be displayed without refreshing the page.
here is my code for following question.
import React , {useState , useContext , useEffect} from 'react'
import { useParams } from 'react-router-dom'
import { JobContext } from '../../context/JobContext'
import { UserContext } from '../../context/UserContext'
import { db } from '../../Firebase'
import Order from './Order'
import './YourOrder.css';
import { Container, Row } from 'react-bootstrap';
import { IoIosShare } from "react-icons/io";
import { BsChevronRight } from "react-icons/bs";
import { Link } from 'react-router-dom'
import { PaymentContext } from '../../context/PaymentContext'
import { OrderContext } from '../../context/OrderContext'
const YourOrder = () => {
//window.location.reload(false)
const [user , setUser]=useContext(UserContext)
const [order , setOrder]=useContext(OrderContext)
const { userrid } = useParams()
const [payment , setPayment]=useContext(PaymentContext)
useEffect(() => {
var priceRef = db.collection("clients").doc(userrid).collection("jobDetails")
priceRef.orderBy("timestamp", "desc").get().then(snapshot=>{
setOrder(snapshot.docs.map((doc) => ({ jobdetailid: doc.id, ...doc.data() })))
})
}, [user , order])
return (
<div className="All_orders_main_container">
<h2 className="text-center mb-2">Your Orders</h2>
{order.length!==0 ?
order.map(item=>{
return item.payment_id!=="" ?<Link to={`/vieworder/${item.jobdetailid}/${userrid}`} >
<Container className="your-orders">
<div className="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 pl-0">
</div>
<div className="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 bordered">
<div className="row">
<div className="col-xl-2 col-lg-2 col-md-4 col-sm-4 col-4">
<img src={item.image} alt="graphic_design_ordered-img" className="order_img"/>
</div>
<div className="col-xl-9 col-lg-9 col-md-6 col-sm-6 col-6 details">
<p className="job_name">{item.Name}</p>
<p className="job_deliverydate">ordered on {item.orderDate}</p>
{/* <p className="job_share pt-1"><IoIosShare className="share_icon"/>Share this item</p> */}
</div>
<div className="col-lg-1 col-md-2 col-sm-2 col-2 open_icon text-right">
<BsChevronRight/>
</div>
</div>
</div>
</Container>
</Link>
: null
})
:
<h1 className="text-center" style={{color : '#c1c1c1', marginTop: 50}}>No Orders</h1>
}
</div>
)
}
export default YourOrder
please guide me for the same
You can use onSnapshot(), which makes your app "listen" for changes on ta document or multiple documents. https://firebase.google.com/docs/firestore/query-data/listen
As we know that the data transfer takes time, we have to either await for the response or, you have to use the onSnapShot() method that will await the response from firebase and then set your list of items,
As per the comment , try removing the [user , order] from the useEffect as it will render your content only if the user or orders list has changes, so instead just pass it as a empty list, thus it will fire on startup,
example :
const [orders, setOrders] = useState([]);
useEffect(()=>{
//The logic here will fire on startup , thus setting your order state from here will work
setOrders() //from here
}, [])
This is the approach for local setup, if you want your data to be globally available, I see you are using context, thus use Reducers to set the state declare a method and call it in here after you get the data
Kindly follow the above approach
Happy Coding
Related
In my nextjs project I'm displaying posts from different tags and each post have many tags. I have a post_by_tags component and I'm using that component in different sections on home page to display posts from different tags. I don't want to show repeating content as some posts have same tags and I have a array to keep post ids that are visible to website. Now I want a way to keep post ids from child component to send back to parent component which updates the array so I can filter out these posts from post object. I find some examples but mostly these are tied with onclick or onchange something like that.
Here is my parent component code:
import Head from 'next/head'
import Image from 'next/image'
import Layout from '../components/Layout';
import Hero from '../components/Hero';
import Developed_country from '../components/Developed_country';
import Posts_by_tags from '../components/Post_by_tags';
import Attorneys from '../components/Attorneys';
import Business_formation from '../components/Business_formation';
import Case from '../components/Case';
export async function getServerSideProps(context) {
// Fetch data from external API
const res = await fetch(`https://dashboard.toppstation.com/api/blogs`);
const data = await res.json();
// Pass data to the page via props
return {
props: { blogs:data}
}
}
export default function Home({blogs}) {
const blog_post_id = [];
const pull_data = (data) => {
console.log(data); // LOGS DATA FROM CHILD)
}
return (
<Layout>
<Hero/>
<Developed_country/>
<Posts_by_tags tag='business' bg='bg_grey' posts={blogs} func={pull_data}/>
<Business_formation/>
<Attorneys/>
<Posts_by_tags tag='png' bg='bg_white' posts={blogs} />
<Posts_by_tags tag='image' bg='bg_grey' posts={blogs} />
<Posts_by_tags tag='png' bg='bg_white' posts={blogs} />
<Case/>
</Layout>
)
}
Child component:
import Blogimg from '../public/img/blog.png';
import btn_arrow from '../public/img/btn_arrow.svg';
import styles from '../styles/Home.module.css';
export default function Posts_by_tags(props){
props.func('My name is xyz');
const bg = props.bg;
let align = ['start','center','end'];
let post_tags = [];
const postIds= [];
const blog_posts = props.posts.filter(bpost=>{
bpost.tags.forEach(tag => {
if(tag.toLowerCase() === props.tag){
return postIds.push(bpost._id);
}
})
});
const posts = props.posts.filter(p => {
if( (postIds.indexOf(p._id) !== -1) && p.visibility==true){
return p;
}
}).slice(0,3);
return(
<>
{posts.length == 0 ? null :(
<section id={styles.postsbytags} className={bg}>
<div className='wrapper'>
<div className="container section posts_by_tags section_ptb">
<div className='row'>
<div className='col-sm-12'>
<h3 className={`${styles.heading3} text-center`}><span className={`${styles.heading3span} ${bg}`}>{props.tag}</span></h3>
</div>
</div>
<div className='row pt_100'>
{posts.map( (post, index) =>(
<div id={`post-${post._id}`} className={`col-md-4 d-flex justify-content-md-${align[index]} justify-content-center`} key={post._id}>
<div className={styles.blog_post}>
<div className={`${styles.blog_image} text-center`}>
<span className={styles.blog_tag}>{props.tag}</span>
<Image className="img-fluid" src={post.image} alt={post.title} width={450} height={400} layout='responsive'/>
</div>
<div className='blog_content'>
<h4 className={styles.blog_title}>{post.title}</h4>
<p className={styles.blog_desc}>{post.description.split(' ').slice(0, 10).join(' ')}...</p>
</div>
</div>
</div>
))}
</div>
<div className='row'>
<div className='col-sm-12'>
<div className='blog_category pt_50'>
<a href="" className={ `btn ${styles.btn_tags} `}>See More {props.tag} <i className={styles.btn_icon}><Image src={btn_arrow} alt="btn-icon"/></i></a>
</div>
</div>
</div>
</div>
</div>
</section>
)}
</>
);
}```
guys its my first time to ask a question here in stackoverflow and i really needs an answer
i have a project which i get data from external api from pinia (similar to VueX) then i pass them into a page then i loop through the data and purse them into a component card to be a dynamic component which renders what ever the data i get
i am having a problem in passing the data into the dynamic component.
i fetched the data successflly in pinia , store it into the state in the store . but cant make it into a variable to loop through them
first iam using typescript
for shop interface ShopData.ts
export default interface ShopData {
id: string
name: string
logoPath: string
address: string
}
for types.ts
export type Shop = ShopData
that is my ShopQueries.ts
import { acceptHMRUpdate, defineStore } from 'pinia'
import type { Shop } from '~/types'
import { getShops } from '~/api/ShopsQueries'
export const useShopQueriesStore = defineStore('ShopQueries', {
state: () => ({
shops: [] as Shop[],
}),
actions: {
async getShops(num: number) {
const response = await getShops(num)
this.shops = response.data
return this.shops
},
},
})
if (import.meta.hot)
import.meta.hot.accept(acceptHMRUpdate(useShopQueriesStore, import.meta.hot))
the page file index.vue
<script setup lang="ts">
import { useShopQueriesStore } from '~/stores/ShopQueries'
import type { Shop } from '~/types'
const shopStore = useShopQueriesStore()
const shops = ref<Shop[] | null>()
onMounted(async() => {
shops.value = await shopStore.getShops(6)
})
</script>
<template>
<div class="row">
<div class="col-md-6 col-xxl-4 mt-3 my-3">
<ShopCard
v-for="shop in shopStore.$state.shops"
:key="shop.id"
:address="shop.address"
:name="shop.name"
:image="shop.logoPath"
/>
</div>
</div>
</template>
Which i also want to make it a card and wraps down and i cant :(
that is the card component ShopCard.vue
<script setup lang="ts">
import type { PropType } from '#vue/runtime-core'
import type { Shop } from '~/types'
const props = defineProps({
shop: null as null | PropType<Shop>,
})
console.log(props)
onMounted(() => {
})
const { shop } = toRefs(props)
</script>
<template>
<div class="card">
<div class="card-body d-flex flex-center flex-column pt-12 p-9">
<div class="symbol symbol-65px symbol-circle mb-5">
<img src="{{shop.image}}" alt="image">
</div>
<a class="fs-4 text-gray-800 text-hover-primary fw-bolder mb-0" href="">{{ shop.name }}</a>
</div>
<div class="fw-bold text-gray-400 mb-6">
{{ shop.address }}
</div>
</div>
</template>
i know its hard .. but i really needs some help please !
the whole task depends on it
waiting for help ...
I am making a blog with React and Sanity, and am trying to use buttons to allow the user to sort blog posts by tag (category). Currently, the sorting works fine if I hard code the tag I want to sort the posts by, but I want to be able to use buttons to change the sort tag. Right now the button is able to change text on the screen to the correct category, but It does not update the visible posts (does not actually sort them).
Here is my code for the blog page:
import React from "react";
import { useState, useEffect } from "react"
import Footer from "../Footer";
import Header from "./Header";
import client from "../../client"
import BlockContent from "#sanity/block-content-to-react";
import { Link } from "react-router-dom";
const Blog = () =>
{
const [posts, setPosts] = useState([])
const [sort, setSort] = useState("all")
useEffect(() => {
client.fetch(
//This line sorts posts by the value of 'keyword'
`*[_type == "post" && $keyword in tags] {
title,
slug,
body,
mainImage {
asset -> {
_id,
url
},
alt
},
tags,
publishedAt
}`,{"keyword":sort} //This line sets the value of 'keyword' to the value of 'sort'
)
.then((data) => setPosts(data))
.catch(console.error)
}, [])
//This function prints the tag that was clicked to the console and updates the
//value of 'sort'. It is supposed to rerender the component to display only the
//posts associated with the tag clicked, but it does not.
function sortPosts(e) {
console.log(e)
setSort(e)
}
return (
<div className = "bg-gray-100 dark:bg-zinc-900">
<Header />
<div className = "" >
<p className = "title pt-32">Welcome to My Blog!</p>
//This line correctly displays the tag that is supposed to determine which posts to display
<p className = "text-center font-semibold">Currently showing: {sort} posts</p>
<div className = "flex items-center justify-center mt-16">
<div className = "grid grid-cols-1 xl:grid-cols-3 lg:grid-cols-2 md:grid-cols-1 gap-10 mx-16">
{posts.map((post) => (
<article key={post.slug.current} className = "rounded-xl max-w-sm bg-white dark:bg-zinc-950 shadow-xl dark:shadow-gray-100/10">
<img src={post.mainImage.asset.url} alt={post.title} className = "object-fill object-center rounded-t-xl" />
<div className = "p-6">
<p className = "text-2xl font-semibold mb-3 dark:text-gray-100">{post.title}</p>
{post.tags.map((tags, key) => (
<div className = "inline-block">
//This line displays a button for each tag associated with the current post and calls the sortPosts function
<button key = {key} onClick={() => sortPosts(tags)} className = "px-2 inline-flex mb-2 mr-2 rounded-2xl hover:bg-white bg-gray-100 dark:hover:bg-zinc-950 dark:bg-zinc-800 dark:text-white duration-300 transition-colors cursor-pointer">{tags}</button>
</div>
))}
<div class = "preview">
<BlockContent blocks={post.body} projectId="2hp9gld0" dataset="production" />
</div>
<button className="button-main items-center mt-2 dark:text-gray-100 block">
<Link to = {`/blog/${post.slug.current}`} className = "">Read Full Article</Link>
</button>
</div>
</article>
))}
</div>
</div>
</div>
<div className = "pb-10 bg-gray-100 dark:bg-zinc-900">
<Footer />
</div>
</div>
)
}
export default Blog;
As I said, this code works perfectly fine other than actually rerendering the correct posts when a button is clicked to sort by a specific tag. Any help is appreciated!
If you fetch data and setPosts in useEffect, You should add sort state to useEffect dependency, to update the posts when you change the sort state value by setSort.
like below:
const [posts, setPosts] = useState([])
const [sort, setSort] = useState("all")
useEffect(() => {
client.fetch(
//This line sorts posts by the value of 'keyword'
...
.then((data) => setPosts(data))
.catch(console.error)
}, [sort])
I'm kinda new to react js, I would be grateful if someone could help me out.
The idea is to have some items (foods) as components and add them to your shopping list and eventually post the final purchase bag to the server.
I have made a component to use as my item card and created a function to add and increase the amount of that item. but when I try to work with the component it affects all the other components.
this is the result of my output. When I add and increase food in a component the other components' amounts continue from the one I added last.
how can I separate the functionally of the same components on a page?
here is the code that I wrote:
import React, { useState } from "react";
var Amount = 0;
function FoodItem(props) {
const [mainDivActivated, mainDivSetStyle] = useState("FoodItemMainContainer");
const [descriptionDivActivated, descriptionSetStyle] =useState("FoodDescription");
const [addButtonDivDisplay, addButtonSetStyle] = useState("PositionReletive");
const [trashButtonDivDisplay, trashButtonSetStyle] = useState("PositionReletive DisplayNone");
const [amountNumber, setAmountNumber] = useState();
var activate = 0;
function OnclickAddToAmount() {
Amount++;
setAmountNumber(Amount);
}
function OnclickRemoveFromAmount() {
Amount--;
setAmountNumber(Amount);
}
function OnclickActivateEvent() {
activateItem();
OnclickAddToAmount();
}
function activateItem() {
mainDivSetStyle("FoodItemMainContainer PrimaryBackgroundGradientColor");
descriptionSetStyle("FoodDescriptionActivated");
addButtonSetStyle("PositionReletive DisplayNone");
trashButtonSetStyle("PositionReletive");
}
function OnclickDeactivateEvent() {
deactivateItem();
OnclickRemoveFromAmount();
}
function deactivateItem() {
mainDivSetStyle("FoodItemMainContainer");
descriptionSetStyle("FoodDescription");
addButtonSetStyle("PositionReletive");
trashButtonSetStyle("PositionReletive DisplayNone");
}
return (
<div className={mainDivActivated}>
<div className="FoodItemContainer">
<div>
<div className="FontSizeXL">{props.foodName}</div>
<div className={descriptionDivActivated}>{props.foodDescription}</div>
</div>
<div className="PositionReletive">
<img
className="VerticallyAndHorizontallyCentered FoodMenuImageCss"
src="/images/temptestpictures/foodImage.jpg"
alt=""
/>
</div>
<div className="PositionReletive FoodItemPriceCss">
<div className="FontSizeXL">Price : {props.foodPrice}</div>
</div>
<div className={addButtonDivDisplay}>
<div
onClick={() => OnclickActivateEvent()}
className="FontSizeXL PrimaryBackgroundGradientColor ColorWhite VerticallyAndHorizontallyCentered WidthFull HorizontallyCenteredText FoodItemAddBtn"
>
Add
</div>
</div>
<div className={trashButtonDivDisplay}>
<div className="VerticallyAndHorizontallyCentered WidthFull HorizontallyCenteredText FoodItemAddBtn">
<div className="AddOrRemoveFoodIconContainer">
{Amount<2 ? (
<span onClick={() => OnclickDeactivateEvent()}className="icon-trashcan AddOrRemoveFoodIcon"></span>
) : (
<span onClick={() => OnclickRemoveFromAmount()}className="icon-minus AddOrRemoveFoodIcon"></span>
)}
<div className="FontSizeXL AddOrremoveNumber">{Amount}</div>
<span onClick={() => OnclickAddToAmount()}className="icon-plus AddOrRemoveFoodIcon"></span>
</div>
</div>
</div>
</div>
</div>
);
}
export default FoodItem;
I'm trying to render a blog as a card then open it up as a page , but its proving to be difficult using Gatsby. I did the exact same thing fine with react using React router but it doesn't seem to be working with Gatsby. I know I can use GraphQL but surely I can do the same thing using REST. Im using Contentful btw
I switched to reach router as suggested in another post but that doesnt work.
I kept getting this error when I used react-router-dom:
Invariant failed: You should not use <Link> outside a <Router>
Fetching Blog contents
function Blog() {
const [blogs, setBlogs] = useState([])
const [image, setImage] = useState()
const [selectedBlog, setSelectedBlog] = useState(blogs)
useEffect(() => {
fetch("http://cdn.contentful.com...")
.then(response => response.json())
.then(data =>
setBlogs(data.items)
)
}, [])
console.log(blogs)
return (
<>
<div className="card-flex" >
{selectedBlog !== null ? blogs.map((blog =>
<Card title={blog.fields.title} date={blog.fields.date} introduction={blog.fields.introduction} mainBody1={blog.fields.mainBody1} mainBody2={blog.fields.mainBody2} setSelectedBlog={selectedBlog}
/>
)):
<Article title={blogs.find(d => d.fields.title === selectedBlog)} />
}
</div>
</>
)
}
export default Blog
Blog Card
function Card(props) {
console.log(props)
return (
<div class="container">
<div class="card">
<div class="card-header">
<img style={{backgroundImage: "url('https://i.pinimg.com/564x/7f/bb/97/7fbb9793b574c32f5d28cae0ea5c557f.jpg')"}}/>
</div>
<div class="card-body">
<span class="tag tag-teal">{props.tags}</span>
<h4>{props.title}</h4>
<p style={{fontSize:"17px", paddingTop:"10px"}} >{props.introduction}</p>
<div class="card-user">
<Link
to={{
pathname: '/article',
state: {
title: props.title,
introduction: props.introduction
}
}}
>
<button>read more</button>
</Link>
<div class="user-info">
<h5 >{ props.date}</h5>
</div>
</div>
</div>
</div>
</div>
)
}
export default Card
**Article **
import React from 'react'
import './Article.css'
import { useLocation } from "#reach/router"
function Article(props) {
// useLocation to access the route state from Blog.js
const { state = {} } = useLocation();
console.log(state)
return (
<div className="main">
<h1 className="title">{state.title}</h1>
<p className="intro">{state.introduction}</p>
<p className="main1">{state.mainBody1}</p>
<p className="main2">{state.mainBody2}</p>
</div>
)
}
export default Article
I think you are mixing stuff. Gatsby extends from #reach/router so you don't need to use its notation. Your Link should look like:
<Link
to={`/article`}
state={{
title: props.title,
introduction: props.introduction
}}
>
Assuming your /article page exists under /pages folder.