Creating a subcollection linked to a specific document ID - Firestore - javascript

Hi everyone,
I'm trying to link comments to existing posts I have in my firestore database.
It almost works.. :) but for some reason everytime I comment on a given post, instead of using the ID of the document already existing in my collection, it just generates a new one (new document in 'posts' with a new automatically generated ID), containing the comment.
Any idea what I, obviously, do wrong?
Here's my code:
function Post({key, profilePic, image, username, timestamp, message}) {
const [{ user }, dispatch] = useStateValue();
const [comments, setComments] = useState([]);
const [comment, setComment] = useState("");
const sendComment = async (e) => {
e.preventDefault();
const commentToSend = comment;
setComment('');
await db.collection('posts').doc(key)
.collection('comments').add ({
comment: commentToSend,
profilePic: user.photoURL,
username: user.displayName,
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
})
}
return (
<div className="flex flex-col">
<div className="p-5 bg-white mt-5 rounded-t-2xl shadow-sm">
<div className="flex items-center space-x-2">
<Avatar
src={profilePic}
className="rounded-full"
/>
<p className="font-medium">{username}</p>
</div>
<div className="pt-2">
{timestamp ? (
<p className="text-xs text-gray-400">
{new Date(timestamp?.toDate()).toLocaleString()}
</p>
) : (
<p className="text-xs text-gray-400">Loading</p>
)}
</div>
<p className="pt-4 pb-4">{message}</p>
{image && (
<div className="relative h-auto bg-white overflow-hidden">
<img src={image} className="object-cover w-full" />
</div>
)}
</div>
<div className="flex justify-between items-center bg-white shadow-md text-gray-400 border-t">
<div className="inputIcon p-3 rounded-none rounded-bl-2xl">
<ThumbUpIcon className="h-4" />
<p className="text-xs sm:text-base">Like</p>
</div>
<div className="inputIcon p-3 rounded-none">
<ChatBubbleOutlineIcon className="h-4"/>
<p className="text-xs sm:text-base">Comment</p>
</div>
</div>
<div className="flex justify-evenly items-center rounded-b-2xl bg-white shadow-md text-gray-400 border-t">
<form className="flex items-center p-4">
<input
type="text"
onChange={e => setComment(e.target.value)}
value={comment}
placeholder="Add a comment.."
className="border-none flex-1 focus:ring-0 outline-none pr-10"
/>
<button
type="submit"
onClick={sendComment}
className="pl-20 font-semibold text-red-400"
>Post</button>
</form>
</div>
</div>
)
}
export default Post
Not sure if it is of importance but here's my Feed.js, rendering my posts:
function Feed() {
const [{ user }, dispatch] = useStateValue();
const [posts, setPosts] = useState([]);
useEffect(() => {
db.collection('posts').orderBy("timestamp", "desc").onSnapshot((snapshot) =>
setPosts(snapshot.docs.map(doc => ({ id: doc.id, data: doc.data()})))
);
}, []);
return (
<div className="flex-grow pb-44 pt-1 mr-4 xl:mr-30">
<div className="mx-auto max-w-md md:max-w-lg lg:max-w-2xl">
{/* <StoryReel /> */}
<MessageSender />
{posts.map(post => (
<Post
key={post.data.id}
profilePic={post.data.profilePic}
message={post.data.message}
timestamp={post.data.timestamp}
username={post.data.username}
image={post.data.image}
/>
))}
</div>
</div>
)
}
export default Feed
Thank you so much for your help!

Related

fetched data from firestore as initial value of useState it gives me udefined value

I want to set the fetched data from firestore as initial value of useState but it gives me undefined value because I want to update user profile and I don't know the user edits or updates which property because I want to keep the other properties of the user the same, only change the edited one.
I've tried this code, but it gives me this error:
Uncaught (in promise) FirebaseError: Function updateDoc() called with invalid data. Unsupported field value: undefined (found in field surname in document users/DQjpLaKYVgVuH9TeqNomIEyuMJB2)
import React, { useState, useEffect } from 'react';
import { useAuthState } from 'react-firebase-hooks/auth';
import { doc, onSnapshot, updateDoc } from "firebase/firestore";
import { auth, db } from '../../firebase';
export default function Form({ setEditForm }) {
const [user, setUser] = useState([]);
const [currentUser] = useAuthState(auth);
// fetching user information from firestore
useEffect(() => {
const getUser = async () => {
const docRef = await doc(db, 'users', currentUser.uid)
try {
await onSnapshot(docRef, (doc) => {
setUser({
...doc.data(), id: doc.id
})
})
} catch (e) {
console.log(e)
}
}
getUser()
}, [])
const [name, setName] = useState(user.firstName);
const [surname, setSurname] = useState(user.surname);
const [biography, setBiography] = useState(user.biography);
const [location, setLocation] = useState(user.location);
// updating user's profile
const updateProfile = async (e) => {
e.preventDefault();
const docRef = doc(db, 'users', currentUser.uid);
await updateDoc(docRef, {
firstName: name,
surname: surname,
biography: biography,
location: location
})
}
console.log(user)
return (
<form
onSubmit={updateProfile}
className="flex flex-col w-4/6 lg:w-3/6"
>
<div className="lg:flex lg:flex-row lg:justify-between lg:gap-6">
<div className="lg:flex lg:flex-col lg:w-1/2">
<h2 className="text-left text-[#4699C2] font-bold py-2">Name: </h2>
<div className="border border-gray-300 rounded-md">
<input
type="text"
placeholder={name}
value={name}
onChange={(e) => setName(e.target.value)}
className="w-full py-2 px-4 opacity-50 focus:opacity-100"
/>
</div>
</div>
<div className="lg:flex lg:flex-col lg:w-1/2">
<h2 className="text-left text-[#4699C2] font-bold py-2">Surname: </h2>
<div className="border border-gray-300 rounded-md">
<input
type="text"
placeholder={surname}
value={surname}
onChange={(e) => setSurname(e.target.value)}
className="opacity-50 px-4 focus:opacity-100 w-full py-2"
/>
</div>
</div>
</div>
<h2 className="text-left text-[#4699C2] font-bold py-2">Biograhpy: </h2>
<div className="border border-gray-300 rounded-md">
<textarea
onChange={(e) => setBiography(e.target.value)}
className="opacity-50 px-4 focus:opacity-100 w-full py-4"
>
{biography}
</textarea>
</div>
<h2 className="text-left text-[#4699C2] font-bold py-2">Location: </h2>
<div className="border border-gray-300 rounded-md">
<input
placeholder={location}
value={location}
onChange={(e) => setLocation(e.target.value)}
className="opacity-50 px-4 focus:opacity-100 w-full py-2"
/>
</div>
<div className="flex flex-row justify-center py-4">
<input
type="submit"
value="SAVE"
className="bg-[#4699C2] text-white fong-bold w-24 py-3 rounded-full mx-4 font-bold hover:bg-[#026FC2] hover:shadow-lg focus:bg-[#026FC2] focus:shadow-lg focus:outline-none focus:ring-0 active:bg-[#026FC2] active:shadow-lg transition duration-150 ease-in-out"
/>
<input
onClick={() => {
setEditForm(false);
}}
type="reset"
value="CANCEL"
className="bg-[#4699C2] cursor-pointer lg:bg-white hover:bg-[#026FC2] hover:text-white hover:shadow-lg focus:bg-[#026FC2] focus:shadow-lg focus:outline-none focus:ring-0 focus:text-white active:bg-[#026FC2] active:shadow-lg transition duration-150 ease-in-out text-white lg:text-[#4699C2] lg:border lg:border-[#4699C2] fong-bold w-24 py-3 rounded-full font-bold"
/>
</div>
</form>
);
}
Answering this as community wiki, As suggested by #yograjtandel, instead of storing the response in one single state, first declare all the states like name, biography, surname, etc... to null. then in useState set all the states ex. setName(doc.data().Name).

TailwindCSS styling applies to one React Component list but not the other

Hello I have two cards but one of them is not applying it's TailwindCSS stuff to the divs at all. I hope it's just some stupid error because I'm kind of scratching my head.
Is the relevant incorrect code:
Where it's being rendered in the index page:
Dashboard.tsx:
<div className="flex flex-col border border-red-700">
{orders.map(
({ id, managerId, invoiceNumber, companyName, contact, partNumbers, partNames, quote, locationOnServer, reportType, createdAt }) => {
return (
<WorkOrderCard id={id} managerId={managerId} invoiceNumber={invoiceNumber} companyName={companyName} contact={contact} partNumbers={partNumbers} partNames={partNames} quote={quote} locationOnServer={locationOnServer} reportType={reportType} createdAt={createdAt} timesheet={[]} />
)
}
)}
And here is the component definition WorkOrderCard.tsx:
export default function WorkOrderCard(props) {
const { id, managerId, invoiceNumber, companyName, contact, partNumbers, partNames, quote, locationOnServer, reportType, createdAt, timesheet} = props;
const [manager, setManager] = React.useState<string>("");
useEffect(() => {
if (manager !== undefined) {
const res = fetch("/api/users/get/" + managerId, {
method: 'GET',
}).then((res) => {
if (res.ok) {
res.json().then((manager) => {
setManager(manager.name);
})
} else {
console.log("There was an error fetching the ticket");
// setErrorMessage(res.statusText)
}
})
}
}, [])
return (
/* Trying to draw an outline around the div but It doesn't appear */
<div className="flex outline outline-red-600">
<div className='flex flex-col'>
<div className="flex flex-row">
<div className="flex">Invoice #{invoiceNumber}</div>
<div className="flex">{companyName}</div>
</div>
<div className="card-body">
<div className="card-text">
<strong>Contact:</strong> {contact || 'N/A'}
</div>
<div className="card-text">
<strong>Part Numbers:</strong>{' '}
{partNumbers.length > 0 ? partNumbers.join(', ') : 'N/A'}
</div>
<div className="card-text">
<strong>Part Names:</strong>{' '}
{partNames.length > 0 ? partNames.join(', ') : 'N/A'}
</div>
<div className="card-text">
<strong>Quote:</strong> ${quote}
</div>
<div className="card-text">
<strong>Location on Server:</strong> {locationOnServer}
</div>
<div className="card-text">
<strong>Report Type:</strong> {reportType}
</div>
<div className="card-text">
<strong>Created At:</strong> {createdAt.toString()}
</div>
<div className="card-text">
</div>
<div className="card-text">
<strong>Manager:</strong> {manager}
</div>
{timesheet.length > 0 && (
<div className="card-text">
<strong>Time Sheet:</strong>
<ul>
{timesheet.map((time) => (
<li key={time.id}>
{new Date(time.date).toLocaleString()} - {new Date(time.date).setHours(new Date(time.date).getHours() + time.hours).toLocaleString()}
</li>
))}
</ul>
</div>
)}
</div>
</div>
</div>
);
};
The working code is called like this Dashboard.tsx:
<div className="flex flex-col justify-evenly border border-red-700">
{tickets.map(
({ id, creator, broken_item, issue_desc, loc, prio, active, creatorName, createdAt }) => {
return (
<TicketGUI className="m-3" id={id} creator={creator} broken_item={broken_item} issue_desc={issue_desc} loc={loc} prio={prio} active={active} name={creatorName} createdAt={createdAt} />
)
}
)}
<div className="flex justify-between m-2">
<button onClick={() => {
ticketPageSelect(currentSession.user.id, tickets[0].id, setTickets, true, pageSize)
}} className="justify-end px-4 py-2 text-sm text-blue-100 bg-blue-500 rounded shadow">
Prev
</button>
<button onClick={() => {
ticketPageSelect(currentSession.user.id, tickets[tickets.length - 1].id, setTickets, false, pageSize)
}} className="justify-end px-4 py-2 text-sm text-blue-100 bg-blue-500 rounded shadow">
Next
</button>
</div>
</div>
And here is the working component TicketGUI.tsx:
export default function TicketGUI(props){
const handlePress = async (e) => {
Router.push('/tickets/'+props.id)
}
return (
<div className="flex flex-col rounded-lg shadow-lg p-2 m-3 outline outline-blue-300">
<div className="flex ">
<img
className="object-cover h-12"
src={props.active ? "/inprocess.png" : "/fixed.png"}
alt="image"
/>
<h1 className=" ml-2 text-xl font-semibold tracking-tight text-blue-600 whitespace-nowrap">
{props.broken_item} - TicketID: {props.id}
</h1>
</div>
<div className="p-4">
<p className="mb-2 leading-normal">
{props.issue_desc}
</p>
<div className="flex w-full">
<button onClick={handlePress} className="px-4 py-2 text-sm text-blue-100 bg-blue-500 rounded shadow">
View Details
</button>
<p className="p-2">
{format(new Date(props.createdAt),'MM/dd/yyyy')}
</p>
</div>
</div>
</div>
);
}
Any help would be appreciated Chat-GPT suggested this but no dice and I factored out className from props:
It looks like the problem is that the className prop is being passed
to the component but it is not being used to apply classes to the
elements within the component. In the code you posted, the className
prop is only being used to specify the component's own class, but it
is not being used to apply classes to the elements within the
component.
To fix this, you can either use the className prop to specify the
classes for each element within the component, or you can use the
className prop to specify the classes for the component itself and
then use the class prop to specify the classes for the elements within
the component.
For example, you could change this line:
<div className={className}>
to this:
<div className={className}>
<div className='flex flex-col'>
<div className="flex flex-row">
...
</div>
<div className="card-body">
...
</div>
</div>
</div>

How to return multiple function in react in JSX format

I'm trying to return a few functions in react but I'm unable to perform as I wanted.
return (
loadingMessage(),
errorMessage(),
loginForm(),
performRedirect()
)
}
I want to return my functions as above but when try this my app directly calls the last function performRedirect(). I don't know whether am I running this correctly or not.
please find the whole code below.
import React, { useState } from "react";
import { Link, Navigate } from "react-router-dom";
import {signin, authenticate, isAutheticated} from "../auth/helper/index"
const Login = () => {
const [values, setValues] = useState({
username: "",
password: "",
error: "",
loading: false,
didRedirect: false,
});
const {username, password, error, loading, didRedirect} = values;
const {user} = isAutheticated();
const handleChange = name => event => {
setValues({ ...values, error: false, [name]: event.target.value });
};
const onSubmit = event => {
event.preventDefault();
setValues({ ...values, error: false, loading: true });
signin({ username, password })
.then(data => {
if (data.error) {
setValues({ ...values, error: data.error, loading: false });
} else {
authenticate(data, () => {
setValues({
...values,
didRedirect: true
});
});
}
})
.catch(console.log("signin request failed", error, user));
};
const performRedirect = () => {
//TODO: do a redirect here
if (didRedirect) {
if (user && user.role === 1) {
return <p>redirect to admin</p>;
} else {
return <p>redirect to user dashboard</p>;
}
}
if (isAutheticated()) {
return <Navigate to="/" />;
}
};
const loadingMessage = () => {
return (
loading && (
<div className="alert alert-info">
<h2>Loading...</h2>
</div>
)
);
};
const errorMessage = () => {
return (
<div className="row">
<div className="col-md-6 offset-sm-3 text-left">
<div
className="alert alert-danger"
style={{ display: error ? "" : "none" }}
>
{error}
</div>
</div>
</div>
);
};
const loginForm = () => {
return (
<div className='bg-gray-200'>
<div className="flex items-center h-screen w-full">
<div className="w-80 bg-white rounded-2xl p-6 m-0 md:max-w-sm md:mx-auto border border-slate-300 shadow-sm">
<div align='center' className='mt-3 mb-3 items-center content-center'> <img src={require('./../data/logo.jpg')} width="120px"/></div>
<span className="block w-full text-xl uppercase font-bold mb-4 text-center">Sign in to EMS
</span>
<form className="mb-0" action="/" method="post">
<div className="mb-4 md:w-full">
<label for="email" className="block text-xs mb-1 text-left text-gray-500">Username</label>
<input onChange={handleChange("username")} className="bg-gray-100 w-full border rounded-2xl px-4 py-2 outline-none focus:shadow-outline text-left text-xs" type="text" name="username" id="username" placeholder="Username" value={username}/>
</div>
<div className="mb-6 md:w-full relative">
<div className='flex w-full'>
<label for="password" className="block text-xs mb-1 text-center text-gray-500">Password</label>
<a className="text-xs text-right text-[#58a6ff] absolute right-0" href="/login">Forgot password?</a></div>
<input onChange={handleChange("password")} className="bg-gray-100 w-full border rounded-2xl px-4 py-2 outline-none focus:shadow-outline text-left text-xs" type="password" name="password" id="password" placeholder="Password" value={password}/>
</div>
<div className="mb-6 md:w-full relative">
<div className='flex w-full'>
<p className="block text-xs mb-1 text-center text-gray-500">{JSON.stringify(values)}</p>
</div>
<button className="bg-green-500 hover:bg-green-700 shadow-lg text-white uppercase text-sm font-semibold px-4 py-2 rounded-2xl text-center items-center w-full" onClick={onSubmit}>Login</button>
</form>
</div>
</div>
</div>
);
};
return (
loadingMessage(),
errorMessage(),
loginForm(),
performRedirect()
)
}
export default Login
Please someone help me on this?
You can modify your return statement with an array value [] like below
return [
loadingMessage(),
errorMessage(),
loginForm(),
performRedirect()
]
Another way, you can render those JSX functions by {} and wrap them into <React.Fragment></React.Fragment> (Or simpler version <></>)
return (
<React.Fragment>
{loadingMessage()}
{errorMessage()}
{loginForm()}
{performRedirect()}
</React.Fragment>)
like this:
return (
<>
{loadingMessage()}
{errorMessage()}
{loginForm()}
{performRedirect()}
</>
)

How to Sort Data In Next js?

I've an ecommerce website and I want to sort Data By Categories , I try to do it with apis but it kill my server , and now i try to do it with redux , that means store the data in the store and filtred from that store but it doesn't work , If any one has an idea how to do that tell me
Container.js
import {useState } from 'react';
import { useRouter } from 'next/router';
import Product from '../Product';
export default function Container({products}){
const router = useRouter();
const [a,setA] = useState(0);
const [b,setB] = useState(6);
const {category} = router.query;
const sidebar = () => {
const sidebar = document.querySelector('.collectionsidebar')
sidebar.classList.remove('-left-full')
sidebar.classList.add('left-0')
}
const previous = () => {
if( a >= 6){
setA(a-=6);
setB(b-=6);
}
}
const next = () => {
if( b < products[0].length)
{
setA(a+=6);
setB(b+=6);
}
}
return(
<section className = " w-full lg:w-3/4 pb-40 lg:pb-22 p-5 space-y-5 h-screen scrollbar">
{/* Filter Part */}
<section className = "relative flex items-center justify-between p-5 bg-gray-50 shadow">
<section className = "lg:hidden">
<i onClick = {sidebar} className='bx bx-filter cursor-pointer text-2xl' />
</section>
<section className = "flex items-center space-x-3 relative">
<select className = "text-xs outline-none p-2 cursor-pointer from-current rounded-full border px-4"
onChange = {e => router.push(`/collections?category=${category ||"all"}&sort=${e.target.value}`)}>
<option value="featured">مميزة</option>
<option value="price-low-to-hight">السعر , من الرخيص الى الاغلى</option>
<option value="price-hight-to-low">السعر , من الاغلى الى الرخيص</option>
<option value="alphabetically-A-Z">أبجديا , ا الى ي</option>
<option value="alphabetically-Z-A">أبجديا , ي الى ا</option>
</select>
<span className="hidden lg:inline-flex text-xs lg:text-sm text-gray-700">صنف حسب </span>
</section>
<p className = "hidden lg:inline text-xs text-gray-700">
<span className = "hover:text-black cursor-pointer" onClick = {() => router.push('/')}> الصفحة الرئيسية </span> / المنتجات
</p>
</section>
{/* Product Feed */}
<section className = "feed grid md:grid-cols-2 lg:grid-cols-3 gap-10 p-1 border-b">
{
products[0].slice(a,b).map(({id_produit,image,Nom,prix,rating,Description,titre,promo})=> (
<Product id = {id_produit} image={image} category={titre} promo={promo} title={Nom} price={prix} description={Description} rating={rating} />
))
}
</section>
{/* Pagination */}
<section className = "justify-center mx-auto flex items-center space-x-5">
{
a >= 6 ? <i onClick={previous}
className='bx bx-left-arrow-alt text-lg rounded-full p-2 text-gray-100 bg-primary active:text-gray-100 cursor-pointer' />
:
<i
className='bx bx-left-arrow-alt text-lg rounded-full p-2 text-gray-400 cursor-not-allowed bg-gray-200 active:bg-sidebar active:text-gray-100' />
}
{
b < products[0].length ? <i onClick={next}
className='bx bx-right-arrow-alt text-lg rounded-full p-2 text-gray-100 bg-primary active:text-gray-100 cursor-pointer' />
: <i
className='bx bx-right-arrow-alt text-lg rounded-full p-2 text-gray-400 cursor-not-allowed bg-gray-100 active:bg-sidebar active:text-gray-100' />
}
</section>
</section>
)
};
SideBar.js
import { useRouter } from 'next/router'
export default function Collection_SideBar({categories}){
const router = useRouter();
return(
<aside className = "w-1/4 text-right border rounded shadow mt-5 mb-44 scrollbar pb-5 space-y-5 hidden lg:inline ">
{/* Category */}
<section className = "space-y-4">
<h3 className = " w-full bg-gray-50 shadow border-gray-900 text-xl font-semibold p-2 font-serif">التصنيفات</h3>
<div className = "space-y-4 px-5">
{categories.map(cat => (
<h5 onClick = {() => router.push(`/collections?category=${cat.titre}`)} key={cat.id_cat} className = " border-b border-gray-100 pb-2 cursor-pointer text-sm hover:text-black text-gray-600 hover:border-gray-300 transform duration-300">{cat.titre}</h5>
))}
</div>
</section>
</aside>
)
}
you can use sort-by package provided by npm :sort-by npm
example :
npm install sort-by
import SortBy from 'sort-by'
const products = [{id: 7,name: 'P1'}, {id: 3,name: 'P2'}, {id: 4,name: 'P3'}];
products.sort(sortBy('name','id'));
I found the solution , I just create a state that called category (in index page) and give the sidebar component the setCategory
index page
export default function Products({products,productsLimit}) {
const items = useSelector(selectItems);
const [categories , setCategories] = useState([]);
const [category , setCategory] = useState([]);
useEffect(async () => await axios.get("/api/products/categories").then(res => setCategories(res.data)),[]);
console.log(category)
const filtredProducts = products[0].filter(val => {
if (category.length === 0) {
return val
} else if (
val.titre
.toString()
.toLowerCase()
.includes(category.toString().toLowerCase())
) {
return val;
}
});
return (
<div className="font-poppins bg-white overflow-hidden h-screen">
<Head>
<title>تسوق الآن</title>
<link rel="icon" href="https://icons-for-free.com/iconfiles/png/512/online+shop+shopping+icon-1320191096068276528.png" />
<link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Fruktur&family=Poppins&display=swap" rel="stylesheet" />
<link rel="stylesheet"href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/>
<meta name="description" content="اشتري مستلزماتك الالكترونية الان بارخص الاثمنة عند كوداتا , الدفع عند الاستلام و كدلك الدفع عبر الحساب البنكي" />
<meta http-equiv="X-UA-Compatible" content="IE=7" />
<meta name="keywords" content="accessoires electronique , مستلزمات الالكترونية , pc portable , حاسوب " />
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</Head>
<Header products={products}/>
<SideBar />
<SearchBar products={products} />
<Basket items={items} />
<ResponsiveSideBar categories = {categories} setCategory = {setCategory} />
<main className = "container mx-auto flex">
<Container products={filtredProducts} productsLimit = {productsLimit} />
<Collection_SideBar categories = {categories} setCategory = {setCategory} />
</main>
</div>
)
}```
SideBar.js
```import { useRouter } from 'next/router'
export default function Collection_SideBar({categories,setCategory}){
const router = useRouter();
return(
<aside className = "w-1/4 text-right border rounded shadow mt-5 mb-44 scrollbar pb-5 space-y-5 hidden lg:inline ">
{/* Category */}
<section className = "space-y-4">
<h3 className = " w-full bg-gray-50 shadow border-gray-900 text-xl font-semibold p-2 font-serif">التصنيفات</h3>
<div className = "space-y-4 px-5">
<h5 onClick = {e => setCategory([])} className = " border-b border-gray-100 pb-2 cursor-pointer text-sm hover:text-black text-gray-600 hover:border-gray-300 transform duration-300">الكل</h5>
{categories.map(cat => (
<>
<h5 onClick = {e => setCategory(cat.titre)} key={cat.id_cat} className = " border-b border-gray-100 pb-2 cursor-pointer text-sm hover:text-black text-gray-600 hover:border-gray-300 transform duration-300">{cat.titre}</h5>
</>
))}
</div>
</section>
</aside>
)
}```

Run or execute script after page is loaded with react helmet, react gatsbyjs

i have a blog post page that load content via graphql, in the content are scripts tag of charts.
the problem is that when using it does not load the scripts. Only load the scripts if you refresh the browser.
So i added the scripts to helmet after data loaded but they dont run/load .
Is there a way to "refresh" the dom?
import React, { useEffect,useState, Suspense } from "react"
import { Link, graphql } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
import EmbedContainer from "react-oembed-container"
import SEO from "../components/seo"
import { Helmet } from "react-helmet"
const PostContentComponent = React.lazy(() => import('../components/PostContentComponent'));
const BlogPost = ({ data }) => {
const [scripts,setScripts] = useState([])
function getScripts () {
// get all script tags from content
const re = /<script\b[^>]*>[\s\S]*?<\/script\b[^>]*>/g
const results = setScripts(data.strapiPost.content.match(re))
return results
}
console.log('scripts', scripts)
useEffect(() => {
getScripts()
// window.instgrm.Embeds.process()
// window.twttr.widgets.load()
}, [data])
return (
<>
<Layout>
<Helmet>
{scripts ? scripts.map((script)=> {
return script
}): null}
</Helmet>
<SEO title={data.strapiPost.title}/>
<section className="posts-container mx-auto all-blog-content my-5 sm:my-20 px-5">
<h3 className="text-1xl sm:text-3xl font-black mb-3">
{data.strapiPost.title}
</h3>
<div className="autor flex flex-wrap items-start">
<div className="autores flex ">
<div className="autorInfo flex items-start">
<h2 className="text-sm tracking-tighter text-gray-900">
By{" "}
{data.strapiPost.users_permissions_users.length === 1 ? (
<>
<Link className="hover:text-black transition duration-300 ease-in-out text-xs mr-1">
{data.strapiPost.users_permissions_users[0].username}
</Link>{" "}
</>
) : data.strapiPost.users_permissions_users.length === 2 ? (
data.strapiPost.users_permissions_users.map((x, index) => (
<>
<Link
className="hover:text-black transition duration-300 ease-in-out text-xs mr-1"
>
{x.name} {x.lastname}{" "}
{index <
data.strapiPost.users_permissions_users.length - 1
? " &"
: ""}
</Link>
</>
))
) : null}
</h2>
</div>
</div>
{/* LOAD CATEGORIES */}
<div className="md:ml-5">
<ul className="flex flex-nowrap relative ">
{data.strapiPost.categories.map(cat => {
return (
<Link
key={cat.name}
className={`bg-gray-200 py-1 px-2 mr-1 rounded-lg text-black text-xs flex-grow `}
>
{cat.name}
</Link>
)
})}
</ul>
</div>
</div>
<span className="text-gray-600 mr-3 text-xs">
Updated at {new Date(data.strapiPost.updated_at).toDateString()}
</span>
<div className="posts-content py-10">
<Img
alt={data.strapiPost.title}
key={data.strapiPost.featured_image.childImageSharp.fluid.src}
imgStyle={{ objectFit: "contain" }}
fluid={data.strapiPost.featured_image.childImageSharp.fluid}
className="mb-10"
/>
<EmbedContainer markup={data.strapiPost.content}>
<div
dangerouslySetInnerHTML={{ __html: unescape(data.strapiPost.content) }}
/>
</EmbedContainer>
</div>
{/* end of all posts */}
{/* AUTHOR CARD */}
<h3 className="text-2xl font-black text-center my-10">
Read More posts by this Author{" "}
</h3>
</section>
<section className="posts-container mx-auto">
<div
className={`grid grid-cols-1 sm:grid-cols-${data.strapiPost.users_permissions_users.length} md:grid-cols-${data.strapiPost.users_permissions_users.length} xl:grid-cols-${data.strapiPost.users_permissions_users.length} gap-4 my-5`}
>
{data.strapiPost.users_permissions_users.map((user, index) => {
return (
<div
key={index}
className="bg-purple-50 flex flex-col items-center justify-center bg-white p-4 shadow rounded-lg"
>
<div className="inline-flex shadow-lg border border-gray-200 rounded-full overflow-hidden h-40 w-40">
{/* <img
src="https://platformable.com/content/images/2020/03/headshot-profile.png"
alt=""
className="h-full w-full my-0"
/> */}
<Img
alt={data.strapiPost.title}
key={index}
fluid={user.image.childImageSharp.fluid}
className="h-full w-full my-0"
/>
</div>
<h2 className="mt-4 font-bold text-xl">
{user.name} {user.lastname}
</h2>
<h6 className="mt-2 text-sm font-medium">{user.position}</h6>
<p className="text-xs text-gray-500 text-center mt-3">
{user.bio}
</p>
</div>
)
})}
</div>
</section>
</Layout>
</>
)
}
export default BlogPost
export const query = graphql`
query MyPost($slug: String!) {
strapiPost(slug: { eq: $slug }) {
categories {
name
}
content
id
title
users_permissions_users {
id
name
lastname
username
image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
position
}
updated_at
featured_image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
`
Have you tried something like this:
<Helmet>
{scripts && scripts.map((script)=> <script>{script}</script>)}
</Helmet>
Based on: https://github.com/gatsbyjs/gatsby/issues/6299#issuecomment-402793089
Alternatively, you can use the custom hook approach (useScript).

Categories