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.
Related
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
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.
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> }
</>
)
}
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 same thing fine with react using React router and useLocation but it doesn't seem to be working with Gatsby.
I switched to reach router as suggested in another post but that doesnt work. Im looking for another method now that perhaps does not need to use useLocation.
I kept getting this error when I used react-router-dom:
Invariant failed: You should not use <Link> outside a <Router>
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 Page
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 believe you're not supposed to use react-router on a Gatsby project: https://www.gatsbyjs.com/docs/reference/routing/creating-routes/
For a normal project you could do:
Go to your top-most element and wrap it with a Router. https://reactrouter.com/web/api/BrowserRouter
You basically have to search for ReactDom.render(<YourApp />) and do ReactDom.render(<Router><YourApp /></Router>)
i'm working on this project that's an implementation of youtube, let's say i search for 'Sia' for example at '/' i get the result back with videos,channels,playlists and when i click on the channel item i route to '/channel' with the channel component now the problem is , when i search for something while at /channel i'm supposed to redirect back to '/' and get the search results with the submitted search term. but i have no idea what's going wrong or if it's a good idea wheather to make the Header component a direct child of the BrowserRouter or render it in each route component along with it's props (which what i went for anyway)
here's the channel component and routing
class ChannelDisplay extends React.Component {
onFormSubmit = (term) => {
this.props.fetchList(term);
this.props.defaultVideo(term);
}
renderHeader() {
const {channel} = this.props
if(!channel.snippet) return <Search/>
if(channel) {
const subNum = `${Number(channel.statistics.subscriberCount).toLocaleString()}`
return (
<div className="channel">
<Header onFormSubmit={this.onFormSubmit}/>
<div className="container">
<img className="img-fluid" src={channel.brandingSettings.image.bannerImageUrl} alt={channel.snippet.title} />
<div className="d-flex flex-nowrap">
<img className="img-thumbnail img-fluid channel-img mx-2 my-2" src={channel.snippet.thumbnails.default.url} alt={channel.snippet.title} />
<div className="media-content">
<p>{channel.snippet.title}</p>
<span><i className="fab fa-youtube mr-2"></i> Subscribe {subNum}</span>
</div>
</div>
</div>
</div>
)
}
}
render() {
return this.renderHeader()
}
}
const mapStateToProps = state => {
return {channel:state.channel}
}
export default connect(mapStateToProps,{fetchList,defaultVideo})
(ChannelDisplay)
.
render() {
return (
<div>
<BrowserRouter>
<div>
<Route path="" exact component={Search} />
<Route path="/channel" exact component={ChannelDisplay} />
</div>
</BrowserRouter>
</div>
)
}
entire code https://github.com/IslamGamal88/minitube
Maybe you should add history.push or history.replace into your submit function in Search.js file, but I think the push is a much better option because you will be able to go back with back button to your channel or video or something.
onFormSubmit = (term) => {
this.props.fetchList(term);
this.props.defaultVideo(term);
this.props.history.push('/');
};