How to use public directory in Vite build - javascript

In my project using Vite (^2.9.7) I have a public folder in my root directory which contains some images.
I'm importing the images using Vite's import.meta.glob function, e.g.
import { LazyBlock } from "../LazyBlock";
const images = import.meta.glob("./home/*.(jpg|png|jpeg)");
export function Gallery() {
const blockImages = Object.keys(images);
return (
<div className="flex justify-center w-full">
<div className="flex flex-wrap justify-center min-h-8">
{blockImages.map((image, index) => (
<LazyBlock url={image} key={index} />
))}
</div>
</div>
);
}
While running in localhost, it works perfectly but there's an annoying warning saying to remove the /public:
files in the public directory are served at the root path.
Instead of /public/home/1.png, use /home/1.png.
But removing it, the images stop working.
But the main problem is when I build and deploy the project, the public folder stop existing and the route used stop working, but if change the src path in devtools, it simply works...
There's some configuration am I missing?

You can't use the Object.keys() since it will always return the absolute path. Instead use Object.values().
You can pass {eager: true,import: 'default'} for the second argument of the Glob Import, so that the return values will just be the public URL of the assets.
You code will look like this.
import { LazyBlock } from "../LazyBlock";
const images = import.meta.glob("./home/*.(jpg|png|jpeg)", {eager: true,import: 'default'});
export function Gallery() {
const blockImages = Object.values(images);
return (
<div className="flex justify-center w-full">
<div className="flex flex-wrap justify-center min-h-8">
{blockImages.map((image, index) => (
<LazyBlock url={image} key={index} />
))}
</div>
</div>
);
}

Related

how to correctly fetch data in getServerSideProps

Using Next.js I came across this problem:
As soon as I reach pages/users, I got this error
./node_modules/mongodb/lib/cmap/auth/gssapi.js:4:0
Module not found: Can't resolve 'dns'
Import trace for requested module:
./node_modules/mongodb/lib/index.js
./models/user/addedUserModel.js
./pages/api/users/index.js
./pages/users.js
https://nextjs.org/docs/messages/module-not-found
I'm trying to fetch all the users from getServerSideProps, inside pages/users
import { Layout, Meta, Card, Button } from "../components/ui";
import {useAxios} from "../utils/hooks/requests/useAxios";
import {useNotifications} from "../context/notifications/notifications_context";
const Users = ({users}) => {
const {handleDeleteRequest} = useAxios("api/users");
const {notification} = useNotifications()
const removeUser = async (_id) => {
await handleDeleteRequest(_id)
}
return (
<>
<Layout>
<Meta title="Users"/>
<Card>
{users.addedUsers.map(user => <div className="flex border-b items-center justify-between"
key={user._id}>
<div className="p-2">
<h2>{user.name}</h2>
</div>
<div>
<Button onClick={() => removeUser(user._id)} className="bg-red-500">Delete</Button>
</div>
</div>)}
</Card>
</Layout>
{notification.text ? <div
className={`${notification.isError ? 'bg-red-500 ' : 'bg-green-500 '} absolute top-0 left-0 w-full p-2 flex items-center justify-center text-white font-semibold`}>
<p>{notification.text}</p>
</div> : null}
</>
)
}
export default Users;
export async function getServerSideProps() {
const res = await fetch("http://localhost:3000/api/users")
const users = await res.json()
return {
props: { users }
}
}
The folder structure of the api endpoint is as follows -> api/users/index.js
Under the pages/users folder I've got an [id].js file to delete a single user.
So the problem lives in the getServerSideProps function or there's something else I'm missing to get rid of this dns error?
Also, I want to re-fetch all the users after removing one of them, to have a fresh users list without refreshing the page. Isn't getServerSideProps useful to do this job??
getServerSideProps allows you to fetch data on the server-side before rendering the page. This means that when a user visits the pages/users page, the data will be fetched from the server and returned as part of the props object to the component

MaxListenersExceedWarning: Possible EventEmitter memory leak detected

A similar issue to the following however I cannot seem to code my way out of it.
Link to similar issue
Possible EventEmitter memory leak detected without EventEmiter
Please find code underneath:
I suspect that the error handling in the 'input onchange' of CreateThread component are causing the issues but at this point I am really not sure about anything anymore. That being said it could be that a connect button in the header could be the culprit being that the console hints at the 'accountChanged Listeners' however I do not recall adding anything unusual. (Adding image for clarity)
Could anyone please shine their light on this issue?
I am already hugely appreciative!
CreateThread.js component
import { abi, contractAddresses } from "../constants";
import { useMoralis } from "react-moralis";
import { useEffect, useState } from "react";
export default function startThread() {
const { chainId: chainIdHex, isWeb3Enabled } = useMoralis();
const chainId = parseInt(chainIdHex);
const threadAddress =
chainIdHex in contractAddresses ? contractAddresses[chainId][0] : null;
const [threadtitle, setthreadtitle] = useState("");
const [threadpost, setthreadpost] = useState("");
const { runContractFunction: createThread } = useWeb3Contract({
abi: abi,
contractAddress: threadAddress,
functionName: "createThread",
params: { _threadTitle: threadtitle, _threadPost: threadpost }, //these parameters should come from the input boxes (document.getElementById("threadtitle").value, etc.)
msgValue: {},
});
async function Update() {
const response = await createThread();
console.log(response);
}
useEffect(() => {
if (isWeb3Enabled) {
}
}, []);
return (
<div>
<div className="bg-slate-400 w-screen h-96 py-4 px-2">
<div>Threadtitle</div>
<input
className=" w-11/12"
id="threadtitle"
onChange={(e) => setthreadtitle(e.target.value)}
></input>
<div>Threadpost</div>
<input
className=" w-11/12 h-24"
id="threadpost"
onChange={(e) => setthreadpost(e.target.value)}
></input>
<div className="py-4">
<button
className="bg-blue-500 hover:bg-blue-400 text-white font-bold py-2 px-4 border-b-4 border-blue-700 hover:border-blue-500 rounded"
onClick={Update}
>
Create Thread
</button>
</div>
</div>
</div>
);
}
Header.js
import { ConnectButton } from "web3uikit";
export default function Header() {
return (
<div className="p-5 border-b-2 flex flex-row bg-slate-400">
<h1 className="py-4 px-4 font-blog text-3xl">
deAgora - Forum for the people, by the people
</h1>
<div className="ml-auto py-2 px-4">
<ConnectButton moralisAuth={false}></ConnectButton>
</div>
</div>
);
}
The issue has seemingly been solved by not constantly rerendering the component which includes the web3uikit connectbutton (which in the above case is the header). I get the sense that on every render the connectbutton adds a listener every time the connectbutton is rendered and does not remove that listener on rerender (someone more with more knowledge on the matter should confirm tho).
I have moved the header out of the routing scheme to always show and therefore it does not rerender on every action performed in the front end (like browsing through the navbar). This seems to have solved the issue.

Conditional render of props in react

I have this 2 states, from 2 different api calls
one is 'movieList' and the other one is 'search', Both are array of movies.
movieList is automatically rendered since it is the search for popular movies and it corresponds that the user is shown as soon as he opens the page, in the navbar I have an input attached to a state called search and it saves an array of movies that match the name in it ... try to use a conditional with the following logic, if search exists, maps search, otherwise map movieList.
but it seems I don't know how to do it correctly. If someone can give me a hand in how to do it, it would help me a lot, thank you very much! here I leave the code
import { useSelector } from 'react-redux'
import { getAllMovies } from '../../features/movieSlice'
import MovieCard from '../MovieCard/MovieCard';
const MovieListing = ({ movieList, search }) => {
return (
<div className='' >
<div className=''>
<div className='my-20 mx-15 flex flex-wrap justify-around items-center' >
{
movieList.map((movie)=>(
<MovieCard {...movie} key={movie.id} />
))}
</div>
</div>
</div>
)
}
export default MovieListing```
To do a conditional render you can try use a ternary operator:
<div className='' >
<div className=''>
<div className='my-20 mx-15 flex flex-wrap justify-around items-center' >
{
search ? search.map((searchItem) => <MapsSearch {...search}/> :
movieList.map((movie) => (<MovieCard {...movie} key={movie.id}/>))
}
</div>
</div>
</div>
(You'll just need to modify the mapping of search and what it returns as I'm not sure what type search is)

Render Component by function Call in React

I am sick of defining states to render Components on condition. Most of the time I just need to show some kind of notification or alert. I want to know how can I render a component by calling a function from that Component.
I have found some sample code that is doing exactly what I want, but I can´t reverse engineer it to implement this on my own as I have no clue how the Modal.info() function is adding itself to the DOM.
I want to recreate the Modal Component for myself and display it by calling MyModal.info().
import { Modal, Button, Space } from 'antd';
const Item = (props: ItemProps) => {
const { itemGroup, items } = props;
function info() {
Modal.info({
title: 'This is a notification message',
content: (
<div>
<p>some messages...some messages...</p>
<p>some messages...some messages...</p>
</div>
),
onOk() {},
});
}
return (
<div className="py-6">
<div
onClick={() => info()}
className="cursor-pointer py-6 px-6 text-3xl font-heading font-bold bg-primary text-white"
>
<p>{itemGroup.text}</p>
</div>
<div className={`${isOpen ? 'block' : 'hidden'} duration-200 transition-all p-3 bg-gray-200`}>
<ul className="grid grid-cols-1 md:grid-cols-2 gap-6">
{items.map((x) => (
<ItemCard key={x.id} itemData={x} />
))}
</ul>
</div>
</div>
);
};
I came up with following solution.
Notification.tsx
import React from 'react';
import ReactDOM from 'react-dom';
export class Notifier {
static warn() {
if (!document) return;
const rootElement = document.getElementById('__next');
ReactDOM.render(React.createElement(Notification), rootElement);
}
}
const Notification = () => {
return (
<div className="w-full h-full bg-red-500 absolute top-0 left-0">Notification Content</div>
);
};
With this solution I can insert anywhere I want my Modal by calling Notifier.warn().
The only thing I am insecure about is the bundle size from ReactDOM which actually ads 125Kb to Notification.tsx.
You should be able to call Modal.info() like this
<Modal.info
title='This is a notification message',
content={) => (
<div>
<p>some messages...some messages...</p>
<p>some messages...some messages...</p>
</div>
)}
onOk={() => {}}
/>;
All functional components can be called like components.
If this doesn't work then Modal.info is not a component.
To trigger it you should follow the first example from the docs.
https://ant.design/components/modal/
You need to manage some sort of state to tell the Modal to open, functional components can manage something like state using hooks.
Like here
https://reactjs.org/docs/hooks-state.html
For custom, you will need to create your own modal design, likely in a react portal, design as you want. But opening/closing will be handled through useState hooks.
import React, { useState } from 'react';
const Component = props => {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Open</Button>
{open && <Modal>
<Button onClick={() => setOpen(false)}>Close</Button>
</Modal> }
</>
)
}

useParams for apollo GraphQL query

I have an issue with my code with react and Apollo Client, i cant get the id in my URL (useParam) and put in my query for apollo i tried lot of possibilities but i cant find the right one.
If you have the right one it will be perfect ;) 🤩
i think the react router part is ok but the problem is to pass the id in my query with apollo , i'am a new graphql user... cool but not easy to understand directkly the concept
const GET_MEETING_ACCESS = gql`
query {
meeting (id:$id){
protectedAccess
}
}
`;
export default function MeetingAccessPage() {
let { id } = useParams();
const { loading, error, data } = useQuery(GET_MEETING_ACCESS, {
variables: { id:id },
});
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<div className='flex flex-col items-center h-screen w-screen bg-gradient-to-r from-blue-600 to-purple-500 bg-gradient-to-r'>
<div className='flex text-center h-auto p-6 flex-col h-1/3'>
<img src={logo} alt="logo" className='flex object-fill' />
<p className='text-white text-xl font-bold pt-6'>{data.Name}</p>
and here my router React
<ApolloProvider client={client}>
<Router>
<Switch>
<Route path="/meeting/:id">
<MeetingAccessPage />
</Route>
</Switch>
</Router>
</ApolloProvider>
You need to update your query to as below
const GET_MEETING_ACCESS = gql`
query Meeting($id: String){
meeting (id:$id){
protectedAccess
}
}
`;
Read more about how to use variables with GraphQl here
You should declare the type of variable you use when you define the graphql query. like this ...
const GET_MEETING_ACCESS = gql`
query my_meeting($id: String!) {
meeting (id:$id){
protectedAccess
}
}
`;
ask me if it is not clear to you.

Categories

Resources