OS: Windows 10 Pro
apollo-client: 1.9.2
react-redux: 5.0.6
So, I'm attempting to read 'connect' a graphql resultset to redux but am receiving the above mentioned error message. My code is as follows:
import { connect } from 'react-redux';
class PhotoGrid extends React.Component {
render () {
const { data } = this.props;
const isNewPage = this.props.location.pathname.includes('new');
if (data.loading) {
return <p>Loading ...</p>;
}
if (data.error) {
return <p>{data.error.message}</p>;
}
return (
<div>
<div>Total record count: {data._allPostsesMeta.count}</div>
<div className="photo-grid">
{ data.allPostses.map( (post,i) => <Photo {...this.props} key={i} postIndexID={i} post={post} />) }
</div>
{isNewPage && (
<div>
<div onClick={() => this.previousPage()}>
Previous
</div>
<div onClick={() => this.nextPage()}>
Next
</div>
</div>
)}
</div>
);
}
};
const allPostsCommentsQuery = graphql(All_Posts_Comments_Query, {
options: ownProps => {
const page = parseInt(ownProps.match.params.page, 10);
const isNewPage = ownProps.location.pathname.includes('new');
const skip = isNewPage ? (page - 1) * parseInt(PRODUCTS_PER_PAGE) : 0;
const first = isNewPage ? parseInt(PRODUCTS_PER_PAGE) : parseInt(PRODUCTS_PER_PAGE);
const orderBy = isNewPage ? OrderBy : null;
fetchPolicy: 'network-only';
return {
variables: {
__offline__: true,
first,
skip,
orderBy,
},
}
},
});
export default connect(allPostsCommentsQuery)(PhotoGrid)
What am I overlooking here?
Related
I am working with redux and I have my actionCreator to add to cart also my reducer function which are below but I keep getting error message which says "actionCreators.js:44 Uncaught TypeError: dispatch is not a function"
My Reducer
import { ADD_TO_CART } from '../action/types';
const init = [];
const addToCartReducer = (state = init, action) => {
switch (action.type) {
case ADD_TO_CART:
return [...state, ...action.payload];
default:
return state;
}
};
export default addToCartReducer;
My Action Creator
export const addToCart = (item) => (dispatch) => {
const product = { ...item, count: 1, sum: item.count * item.prices[0].amount };
dispatch({
type: ADD_TO_CART,
payload: product,
});
};
Component where I am using it
import React, { Component } from 'react';
class Products extends Component {
constructor(props) {
super(props);
this.state = '';
}
render() {
const {
products, addProductImage, centered, imageContainer, currency, addToCart, **Passed it as props**
} = this.props;
const allProducts = !products ? '' : products.products.map((product) => (
<article className="card" key={product.id}>
<div style={imageContainer}>
<img className="card_image1" src={product.gallery[0]} alt={product.name} />
{product.inStock ? (
<img
src={addProductImage}
alt={product.name}
style={{ cursor: 'pointer' }}
onClick={addToCart(product)} **Here I call it**
/>
)
: null}
{!product.inStock ? (<div style={centered}>Out of stock</div>) : null}
</div>
<div>
<div>{product.name}</div>
<div>{`${currency} ${product.prices[0].amount}`}</div>
</div>
</article>
));
return (
<>{allProducts}</>
);
}
}
export default Products;
But I get this error message
I have tried to use it without props, I mean by calling it direct to that component but to no progress.
the actionCreator is a function that returns an action
export const addToCart = (product) => ({
type: ADD_TO_CART,
payload: product,
});
Now to call the action creator in class component you need to use the connect function from redux
import React, { Component } from 'react';
class Products extends Component {
constructor(props) {
super(props);
this.state = '';
}
render() {
const {
products, addProductImage, centered, imageContainer, currency, addToCart, **Passed it as props**
} = this.props;
const allProducts = !products ? '' : products.products.map((product) => (
<article className="card" key={product.id}>
<div style={imageContainer}>
<img className="card_image1" src={product.gallery[0]} alt={product.name} />
{product.inStock ? (
<img
src={addProductImage}
alt={product.name}
style={{ cursor: 'pointer' }}
onClick={() => addToCart({ ...product, count: 1, sum: product.count * product.prices[0].amount })}
/>
)
: null}
{!product.inStock ? (<div style={centered}>Out of stock</div>) : null}
</div>
<div>
<div>{product.name}</div>
<div>{`${currency} ${product.prices[0].amount}`}</div>
</div>
</article>
));
return (
<>{allProducts}</>
);
}
}
const mapDispatchToProps = {
addToCart,
}
export default connect(null, mapDispatchToProps)(Products);
Reducer
import { ADD_TO_CART } from '../action/types';
const init = [];
const addToCartReducer = (state = init, action) => {
switch (action.type) {
case ADD_TO_CART:
return [...state, action.payload];
default:
return state;
}
};
export default addToCartReducer;
here is my folder stucture
shop
- [categorySlug]
- [productSlug]
- index.tsx
- index.tsx
index.tsx
graphql calling will be
/shop/shoes/nike-1
/shop/jersey/jersey-1
[categorySlug] index.tsx
export function ShopCategoryComponent({ products }): JSX.Element {
const { query } = useRouter();
const router = useRouter();
const categorySlug = hasCategorySlug(query) ? query.categorySlug : undefined;
const viewProductDeatails = useCallback(
(productSlug) => {
router.push(`/shop/${categorySlug}/${productSlug}`);
},
[router]
);
return (
<section>
{products.map((product) => (
<div
key={`${product.id}`}
onClick={() => viewProductDeatails(product.slug)}
>
<h3>{product.name}</h3>
<h3>{product?.$on['SimpleProduct'].price()}</h3>
<img src={product?.$on['SimpleProduct'].image.sourceUrl()} />
</div>
))}
</section>
);
}
export default function ShopCategory() {
const { useQuery } = client;
const { query } = useRouter();
const { products } = useQuery();
const categorySlug = hasCategorySlug(query) ? query.categorySlug : undefined;
const generalSettings = useQuery().generalSettings;
const setProducts = products({
where: {
categoryIn: categorySlug,
},
}).nodes;
return (
<React.Fragment>
<Menu />
<main className='content content-single'>
<ShopCategoryComponent products={setProducts} />
</main>
<Footer copyrightHolder={generalSettings.title} />
</React.Fragment>
);
}
when i click on the image it will then go to the productSlug page to show single product detail, it work sometimes, sometimes it will be undefined, like this.i wonder where i did wrong to cause this ?
/shop/shoes/undefined
it happen because of re-hydration and the categorySlug and productSlug have not get slug and it show undefined. also i mess up my variable categorySlug.
1.change
const categorySlug = hasCategorySlug(query) ? query.categorySlug : undefined;
to
const categorySlug = query.categorySlug
2.add
export function ShopCategoryComponent({ products }): JSX.Element {
const { query, isReady } = useRouter();
const categorySlug = query.categorySlug;
// pre-render page check, show loading if data havet get it.
if (!isReady) {
return (
<div>
<h1>Loading...</h1>
</div>
);
}
}
now everything work fine now. thanks user8566930
I tried to implement a simple UI for smart contracts using polkadot.js in the next.js framework.
The content of the WEB UI is a simple one that calls the Flipper contract, which is famous for the sample contract of the substrate.
When compiling, the following error is output. Can you tell me how to solve it?
Souce Code:
import { useEffect, useState } from "react";
import {
web3Accounts,
web3Enable,
web3FromSource,
} from "#polkadot/extension-dapp";
import { InjectedAccountWithMeta } from "#polkadot/extension-inject/types";
const Home = () => {
const [allAccount, setAllAccount] = useState<InjectedAccountWithMeta[]>([]);
const getAccounts = async () => {
const extensions = await web3Enable("my cool dapp");
if (extensions.length === 0) {
return;
}
const allAccounts = await web3Accounts();
setAllAccount(allAccounts);
};
useEffect(() => {
getAccounts();
}, []);
return (
<>
<div>
{typeof allAccount !== "undefined"
? allAccount.map((account) => {
return (
<div key={account.address}>
<div className="font-bold mb-2 text-white">
{account.address}
</div>
</div>
);
})
: ""}{" "}
</div>
</>
);
};
export default Home;
Error Information:
> Build error occurred
ReferenceError: window is not defined
at file:///Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/#polkadot/extension-dapp/bundle.js:10:13
at ModuleJob.run (node:internal/modules/esm/module_job:175:25)
at async Loader.import (node:internal/modules/esm/loader:178:24)
at async importModuleDynamicallyWrapper (node:internal/vm/module:437:15) {
type: 'ReferenceError'
}
This issue occurs because next.js is a framework for server-side rendering.
In order to avoid this problem, it is necessary to control not to execute
server-side rendering for the relevant part.
Componentize the part that gets account information from the relevant Extension.
Adopt dynamic import when using this component and set server-side rendering to off.
component sample code:
import { useEffect, useState } from "react";
import { web3Accounts, web3Enable } from "#polkadot/extension-dapp";
import { InjectedAccountWithMeta } from "#polkadot/extension-inject/types";
const Extention = () => {
const [allAccount, setAllAccount] = useState<InjectedAccountWithMeta[]>([]);
const getAccounts = async () => {
const extensions = await web3Enable("my cool dapp");
if (extensions.length === 0) {
return;
}
const allAccounts = await web3Accounts();
setAllAccount(allAccounts);
};
useEffect(() => {
getAccounts();
}, []);
return (
<>
<div>
{typeof allAccount !== "undefined"
? allAccount.map((account) => {
return (
<div key={account.address}>
<div className="font-bold mb-2 text-white">
{account.address}
</div>
</div>
);
})
: ""}{" "}
</div>
</>
);
};
export default Extention;
Calling component sample code:
import dynamic from "next/dynamic";
import { useState } from "react";
const Extention = dynamic(() => import("../component/extention"), {
ssr: false,
});
const Home = () => {
const [showExtention, setShowExtention] = useState(false);
return (
<>
<button onClick={() => setShowExtention(true)}>show extention</button>
{showExtention == true && <Extention></Extention>}
</>
);
};
export default Home;
Uncaught Error: When called with an action of type "DELITEM", the slice reducer for key "addItem" returned undefined. To ignore an action, you must explicitly return the previous state. If you want this reducer to hold no value, you can return null instead of undefined.
What is this error when I open inspection. My problem is that Onclick is not working in my app.
Here is the code:
import React from 'react'
import { useSelector } from 'react-redux'
import { useDispatch } from 'react-redux'
import { delItem } from '../redux/actions/index'
import { NavLink } from 'react-router-dom'
const Cart = () => {
const state = useSelector((state)=> state.addItem)
const dispatch = useDispatch()
const handleClose = (item) => {
dispatch(delItem(item))
}
const cartItems = (cartItem) => {
return(
<div className="px-4 my-5 bg-light rounded-3" key={cartItem.id}>
<div className="container py-4">
<button onClick={()=>handleClose(cartItem)} type="button" className="btn-close float-end" aria-label="Close"></button>
<div className="row justify-content-center">
<div className="col-md-4">
<img src={cartItem.image} alt={cartItem.title} height="200px" width="180px" />
</div>
<div className="col-md-4">
<h3>{cartItem.title}</h3>
<p className="lead fw-bold">${cartItem.price}</p>
</div>
</div>
</div>
</div>
);
}
Action:
export const addItem = (product) => {
return {
type : "ADDITEM",
payload : product
}
}
export const delItem = (product) => {
return {
type : "DELITEM",
payload : product
}
}
Reducers:
const addItem = [];
const addItems = (state = addItem, action) => {
switch (action.type) {
case "ADDITEM": return [
...state,
action.payload
]
break;
case "DELITEM": return
return state = state.filter((x)=>{
return x.id !== action.payload.id
})
break;
default: return state;
break;
}
}
export default addItems;
case "DELITEM": return
return state = state.filter((x)=>{
return x.id !== action.payload.id
})
change above code to :
make it to "DELITEM": return [...state.filter((x)=>{
return x.id !== action.payload.id
})]
I am using Apollo GraphQL to fetch posts to populate a next js project.
The code I currently have works but I would like to implement the loading state of useQuery instead of what I have below.
This is the index (Posts page if you will)
import Layout from "../components/Layout";
import Post from "../components/Post";
import client from "./../components/ApolloClient";
import gql from "graphql-tag";
const POSTS_QUERY = gql`
query {
posts {
nodes {
title
slug
postId
featuredImage {
sourceUrl
}
}
}
}
`;
const Index = props => {
const { posts } = props;
return (
<Layout>
<div className="container">
<div className="grid">
{posts.length
? posts.map(post => <Post key={post.postId} post={post} />)
: ""}
</div>
</div>
</Layout>
);
};
Index.getInitialProps = async () => {
const result = await client.query({ query: POSTS_QUERY });
return {
posts: result.data.posts.nodes
};
};
export default Index;
Then it fetches an individual Post
import Layout from "../components/Layout";
import { withRouter } from "next/router";
import client from "../components/ApolloClient";
import POST_BY_ID_QUERY from "../queries/post-by-id";
const Post = withRouter(props => {
const { post } = props;
return (
<Layout>
{post ? (
<div className="container">
<div className="post">
<div className="media">
<img src={post.featuredImage.sourceUrl} alt={post.title} />
</div>
<h2>{post.title}</h2>
</div>
</div>
) : (
""
)}
</Layout>
);
});
Post.getInitialProps = async function(context) {
let {
query: { slug }
} = context;
const id = slug ? parseInt(slug.split("-").pop()) : context.query.id;
const res = await client.query({
query: POST_BY_ID_QUERY,
variables: { id }
});
return {
post: res.data.post
};
};
export default Post;
Whenever I have tried to use the useQuery with '#apollo/react-hooks' I always end up with a data.posts.map is not a function.
When you use useQuery, you should not destructure the data like result.data.posts.nodes because the data field will be undefined and loading is true for the first time calling. That why you got an error data.posts.map is not a function. Then if your query fetch data successfully, the loading field will be false.
You can try it:
import Layout from "../components/Layout";
import Post from "../components/Post";
import client from "./../components/ApolloClient";
import { useQuery } from "#apollo/react-hooks"
import gql from "graphql-tag";
const POSTS_QUERY = gql`
query {
posts {
nodes {
title
slug
postId
featuredImage {
sourceUrl
}
}
}
}
`;
const Index = props => {
const { posts } = props;
const { loading, error, data } = useQuery(POSTS_QUERY);
if (loading) return <div>Loading...</div>
if (error) return <div>Error</div>
return (
<Layout>
<div className="container">
<div className="grid">
{data.posts.nodes.length
? data.posts.nodes.map(post => <Post key={post.postId} post={post} />)
: ""}
</div>
</div>
</Layout>
);
};