I am playing with the Meteor Apollo demo repo.
I am having difficulty passing variables down to children with React. I am getting an error
imports/ui/Container.jsx:10:6: Unexpected token (10:6)
The below code is the Container.jsx component:
import React from 'react';
import { Accounts } from 'meteor/std:accounts-ui';
class Container extends React.Component {
render() {
let userId = this.props.userId;
let currentUser = this.props.currentUser;
}
return (
<Accounts.ui.LoginForm />
{ userId ? (
<div>
<pre>{JSON.stringify(currentUser, null, 2)}</pre>
<button onClick={() => currentUser.refetch()}>Refetch!</button>
</div>
) : 'Please log in!' }
);
}
}
It is passed props via the Meteor Apollo data system (I have omitted some imports at the top):
const App = ({ userId, currentUser }) => {
return (
<div>
<Sidebar />
<Header />
<Container userId={userId} currentUser={currentUser} />
</div>
)
}
// This container brings in Apollo GraphQL data
const AppWithData = connect({
mapQueriesToProps({ ownProps }) {
if (ownProps.userId) {
return {
currentUser: {
query: `
query getUserData ($id: String!) {
user(id: $id) {
emails {
address
verified
}
randomString
}
}
`,
variables: {
id: ownProps.userId,
},
},
};
}
},
})(App);
// This container brings in Tracker-enabled Meteor data
const AppWithUserId = createContainer(() => {
return {
userId: Meteor.userId(),
};
}, AppWithData);
export default AppWithUserId;
I would really appreciate some pointers.
I believe the error is that you accidentally ended the render function before the return statement.
render() { // <- here it starts
let userId = this.props.userId;
let currentUser = this.props.currentUser;
} // <- here it ends
Another error is that your return statement doesn't return a single DOM element, but two of them: an Accounts.ui.LoginForm and a div. The return function should only return one element. Just put the entire thing into a single <div>.
Related
this is my index code and I want to transfer / send this data to another page
I try this code but it's not working I don't why
import { useRouter } from "next/router";
function index() {
const router = useRouter();
const [inputValue, setInputValue] = useState("");
const handleImgInput = (e) => {
e.preventDefault();
router.push({
pathname: "/createproject/uploadnfts/nftdetails",
query: inputValue,
});
};
return (
<form action="" onSubmit={handleImgInput}>
<input
type="email"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
</form>
);
}
this is the data page code. when this page open, I didn't receive the input value from my index page and also what i input in the index file, it appears to my localhost link like this:
http://localhost:3001/data?demo#gmail.com
import { useRouter } from "next/router";
import React from "react";
function Data() {
const router = useRouter();
const {
query: { inputValue },
} = router;
const props = {
inputValue,
};
console.log(props);
return (
<div>
<p>{inputValue}</p>
</div>
);
}
export default Data;
The query property in the router options requires passing an object to it. The query params are formed from the key-value pairs in the object.
See below example from the Next.js docs:
import { useRouter } from 'next/router'
export default function ReadMore({ post }) {
const router = useRouter()
return (
<button
type="button"
onClick={() => {
router.push({
pathname: '/post/[pid]',
query: { pid: post.id },
})
}}
>
Click here to read more
</button>
)
}
Taken from: https://nextjs.org/docs/api-reference/next/router#with-url-object
In your case, this would be something like:
const handleImgInput = (e) => {
e.preventDefault();
router.push({
pathname: "/createproject/uploadnfts/nftdetails",
query: { value: inputValue },
});
};
When you want to access the query params, make sure to reference them like an object's properties. For the example above, this would be:
const { value } = router.query;
I'm trying to deploy my NextJs app (using GraphCMS) on Vercel. When I build the app on my computer it works fine, I can build and run the app locally but once I try to deploy the same exact app on Vercel it crash with this error
TypeError: Cannot read properties of undefined (reading 'document')
at Object.parseRequestExtendedArgs (/vercel/path0/node_modules/graphql-request/dist/parseArgs.js:37:25)
at /vercel/path0/node_modules/graphql-request/dist/index.js:422:42
at step (/vercel/path0/node_modules/graphql-request/dist/index.js:63:23)
at Object.next (/vercel/path0/node_modules/graphql-request/dist/index.js:44:53)
at /vercel/path0/node_modules/graphql-request/dist/index.js:38:71
at new Promise ()
at __awaiter (/vercel/path0/node_modules/graphql-request/dist/index.js:34:12)
at request (/vercel/path0/node_modules/graphql-request/dist/index.js:418:12)
at getPosts (/vercel/path0/.next/server/chunks/104.js:1143:82)
at getStaticPaths (/vercel/path0/.next/server/pages/post/[slug].js:98:86)
Build error occurred
Error: Failed to collect page data for /post/[slug]
at /vercel/path0/node_modules/next/dist/build/utils.js:959:15
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
type: 'Error'
}
error Command failed with exit code 1.
I don't understand where this is coming from.
pages/post/[slug].js
import React from "react";
import { useRouter } from "next/router";
import {
PostDetail,
Categories,
PostWidget,
Author,
Comments,
CommentsForm,
Loader,
} from "../../components";
import { getPosts, getPostDetails } from "../../services";
import { AdjacentPosts } from "../../sections";
const PostDetails = ({ post }) => {
const router = useRouter();
if (router.isFallback) {
return <Loader />;
}
return (
<>
<div className="container mx-auto px-10 mb-8">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12">
<div className="col-span-1 lg:col-span-8">
<PostDetail post={post} />
<Author author={post.author} />
<AdjacentPosts slug={post.slug} createdAt={post.createdAt} />
<CommentsForm slug={post.slug} />
<Comments slug={post.slug} />
</div>
<div className="col-span-1 lg:col-span-4">
<div className="relative lg:sticky top-8">
<PostWidget
slug={post.slug}
categories={post.categories.map((category) => category.slug)}
/>
<Categories />
</div>
</div>
</div>
</div>
</>
);
};
export default PostDetails;
// Fetch data at build time
export async function getStaticProps({ params }) {
const data = await getPostDetails(params.slug);
return {
props: {
post: data,
},
};
}
// Specify dynamic routes to pre-render pages based on data.
// The HTML is generated at build time and will be reused on each request.
export async function getStaticPaths() {
const posts = await getPosts();
return {
paths: posts.map(({ node: { slug } }) => ({ params: { slug } })),
fallback: false,
};
}
here is the Graphql query getPosts
export const getPosts = async () => {
const query = gql`
query MyQuery {
postsConnection {
edges {
cursor
node {
author {
bio
name
id
photo {
url
}
}
createdAt
slug
title
excerpt
displayedDate
featuredImage {
url
}
categories {
name
slug
}
}
}
}
}
`;
const result = await request(graphqlAPI, query);
return result.postsConnection.edges;
};
getPostDetails
export const getPostDetails = async (slug) => {
const query = gql`
query GetPostDetails($slug: String!) {
post(where: { slug: $slug }) {
title
excerpt
featuredImage {
url
id
}
author {
name
bio
photo {
url
}
}
createdAt
slug
content {
raw
}
categories {
name
slug
}
displayedDate
}
}
`;
const result = await request(graphqlAPI, query, { slug });
return result.post;
};
I really don't understand why I can build it locally but not en Vercel, Thanks
Tried to modify queries, turn off fallback and others things that did not work
I'm trying to render a quiz object from an api and am using useEffect to do so, but it doesn't seem to be working.
Here is my Quiz component:
export function Quiz(props) {
const {
quiz,
fetchQuiz,
} = props;
useEffect(() => {
fetchQuiz();
}, [])
return (
<div id="wrapper">
{ quiz.question }
</div>
)
}
const mapStateToProps = state => {
return {
quiz: state.quiz,
}
}
export default connect(mapStateToProps, {
fetchQuiz,
})(Quiz)
my action creator:
export function fetchQuiz() {
return function (dispatch) {
axios. get('http://localhost:9000/api/quiz/next')
.then(res => {
dispatch({ type: SET_QUIZ_INTO_STATE, payload: res.data })
})
.catch(err => console.error(err))
}
}
my reducer:
const initialQuizState = null
function quiz(state = initialQuizState, action) {
switch(action.type) {
case SET_QUIZ_INTO_STATE:
return action.payload
default:
return state
}
}
So when I console.log "quiz" in my Quiz component, I get the object that I am expecting and it's all good. But when I try and call "quiz.question" I get the error: Cannot read properties of null (reading question). Which leads me to believe useEffect is not loading the data from the api correctly. Am I doing something else wrong?
When accessing an object from an API response in the DOM, make sure you have a conditional to check for completion like so:
return (
<div id="wrapper">
{ quiz ? quiz.question : 'No Quiz Here' }
</div>
)
}
I'm building navigation to my App,
and I'm trying to give the navigation certain conditions on which to navigate around.
for example:haveFilledForm ? go to screen x : go to screen y
Those conditions are base on currentUser object which i get from Firebase Live DataBase
I configure a database.js with functions to use the live database, this is my Get User Function From Database:
export const getUser = async (uid) => {
firebase
.database()
.ref("users/" + uid)
.once("value")
.then((snap) => {
console.log(snap);
return snap;
});
};
Now, I manage different navigators from one main file called AppNavigator.js
In this file I'm try to get user Information and redirect user according to his props from the livedatabase which i get using firebase.auth()
Here is this page:
import * as React from "react";
import { NavigationContainer } from "#react-navigation/native";
import { AuthStack } from "./AuthStack";
import { TabNavigator } from "./TabNavigator";
import PersonalInfo from "../screens/Auth/PersonalInfo";
import firebase from "../util/firebase";
import { AppLoading } from "expo";
import { getUser } from "../util/database";
export default class AppNavigator extends React.Component {
constructor(props) {
super(props);
this.state = {
user: "",
isLoading: true,
isFilled: false,
userInfo: {},
};
}
componentDidMount() {
firebase.auth().onAuthStateChanged(async (user) => {
if (user) {
console.log("logged in " + JSON.stringify(user.uid));
this.setState({ user });
} else {
console.log("not logged in");
this.setState({ user: "" });
this.setState({ isLoading: false });
}
getUser(this.state.user.uid)
.then((usr) => {
console.log(usr + " usr");
this.setState({ userInfo: usr });
this.setState({ isLoading: false });
})
.then(console.log("Imlast"));
});
}
render() {
if (this.state.isLoading) {
return <AppLoading />;
} else {
return (
<NavigationContainer>
{this.state.user ? (
this.state.userInfo ? (
<TabNavigator />
) : (
<PersonalInfo />
)
) : (
<AuthStack />
)}
</NavigationContainer>
);
}
}
}
the console.log output from this page is:
logged in "jmC6C5quEFSY0cFBfT8dqJe5E8a2"
Imlast
undefined usr
Object {
"admin": false,
"credit": 0,
"injuries": "",
"isProfileFilled": true,
"phone": "",
}
Now I can't seem to understand why Imlast is printed before the user object,
I understand that it got something to do with Event Loop and the fact that firebase is async.
So what is the right way to achieve this?
Eventually my end goal is to redirect user based on his "isProfileFilled" value from database
The reason Im last is printed before undefined usr is because .then accepts a callback function but you pass it a statement. So when the js interpreter goes over your code it executes the console.log immediately instead of waiting for it to be invoked when the promise is resolved. This how you can fix it:
getUser(this.state.user.uid)
.then((usr) => {
console.log(usr + " usr");
this.setState({ userInfo: usr });
this.setState({ isLoading: false });
})
.then(() => console.log("Imlast"));
//Instead of .then(console.log("Imlast"));
Changing state in react is asynchronous! Which means that when you call setState in the next line this.state isn't guaranteed to equal the new state.
I suggest you use the user object you receive in the callback like this: getUser(user.uid). In addition to that it seems redundant to save the user twice in the component state(user and userInfo).
Instead of saving an empty string for a user to represent there is no user, just initialize it as null in the ctor.
Lastly to show different components base on isProfileFilled you can do it like this:
render() {
const { user, isLoading } = this.state
if (isLoading) {
return <AppLoading />;
} else if(!user) {
return <AuthStack />
} else {
return <NavigationContainer>
{user.isProfileFilled ? <TabNavigator /> : <PersonalInfo />}
</NavigationContainer>
}
}
My NextJS project has been giving me grief over Graph QL these days. I've been trying to implement an Apollo client solution to retrieve data from a remote GraphQL server into a custom component. But no matter which solution I try, I always end up with this error. Here's my current react-apollo implementation:
// /lib/with-apollo-client.js
import React from "react";
import Head from "next/head";
import { getDataFromTree } from "react-apollo";
import initApollo from "./init-apollo";
export default App => {
return class WithData extends React.Component {
static displayName = `WithData(${App.displayName})`;
static async getInitialProps(ctx) {
const { Component, router } = ctx;
const apollo = initApollo({});
ctx.ctx.apolloClient = apollo;
let appProps = {};
if (App.getInitialProps) {
appProps = await App.getInitialProps(ctx);
}
// Run all GraphQL queries in the component tree
// and extract the resulting data
if (!process.browser) {
try {
// Run all GraphQL queries
await getDataFromTree(
<App
{...appProps}
Component={Component}
router={router}
apolloClient={apollo}
/>
);
} catch (error) {
console.error("Error while running `getDataFromTree`", error);
}
// getDataFromTree does not call componentWillUnmount
// head side effect therefore need to be cleared manually
Head.rewind();
}
// Extract query data from the Apollo store
const apolloState = apollo.cache.extract();
return {
...appProps,
apolloState
};
}
constructor(props) {
super(props);
this.apolloClient = initApollo(props.apolloState);
}
render() {
return <App {...this.props} apolloClient={this.apolloClient} />;
}
};
};
// /lib/init-apollo.js
import { ApolloClient, InMemoryCache, HttpLink } from 'apollo-boost'
import fetch from 'isomorphic-unfetch'
let apolloClient = null
// Polyfill fetch() on the server (used by apollo-client)
if (!process.browser) {
global.fetch = fetch
}
function create (initialState) {
// Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient
return new ApolloClient({
connectToDevTools: process.browser,
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
link: new HttpLink({
uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute)
credentials: 'same-origin' // Additional fetch() options like `credentials` or `headers`
}),
cache: new InMemoryCache().restore(initialState || {})
})
}
export default function initApollo (initialState) {
// Make sure to create a new client for every server-side request so that data
// isn't shared between connections (which would be bad)
if (!process.browser) {
return create(initialState)
}
// Reuse client on the client-side
if (!apolloClient) {
apolloClient = create(initialState)
}
return apolloClient
}
The component I'm retrieving data into looks like this:
// /components/PostsList2.jsx
import { Query } from 'react-apollo'
import gql from 'graphql-tag'
export const allUsersQuery = gql`
query allUsers($first: Int!, $skip: Int!) {
allUsers(orderBy: createdAt_DESC, first: $first, skip: $skip) {
id
firstName
createdAt
}
_allUsersMeta {
count
}
}
`
export const allUsersQueryVars = {
skip: 0,
first: 10
}
export default function PostsList2 () {
return (
<Query query={allUsersQuery} variables={allUsersQueryVars}>
{({ loading, error, data: { allUsers, _allUsersMeta }, fetchMore }) => {
if (error) return <aside>Error loading users!</aside>
if (loading) return <div>Loading</div>
const areMorePosts = allUsers.length < _allUsersMeta.count
return (
<section>
<ul>
{allUsers.map((user, index) => (
<li key={user.id}>
<div>
<span>{index + 1}. </span>
<div>{user.firstName}</div>
</div>
</li>
))}
</ul>
{areMorePosts ? (
<button onClick={() => loadMorePosts(allUsers, fetchMore)}>
{' '}
{loading ? 'Loading...' : 'Show More'}{' '}
</button>
) : (
''
)}
</section>
)
}}
</Query>
)
}
function loadMorePosts (allUsers, fetchMore) {
fetchMore({
variables: {
skip: allUsers.length
},
updateQuery: (previousResult, { fetchMoreResult }) => {
if (!fetchMoreResult) {
return previousResult
}
return Object.assign({}, previousResult, {
// Append the new users results to the old one
allUsers: [...previousResult.allUsers, ...fetchMoreResult.allUsers]
})
}
})
}
Since this is a NextJS project, there's also an _app.jsx that I've wrapped in a special provider component:
// /pages._app.jsx
/* eslint-disable max-len */
import '../static/styles/fonts.scss';
import '../static/styles/style.scss';
import '../static/styles/some.css';
import CssBaseline from '#material-ui/core/CssBaseline';
import { ThemeProvider } from '#material-ui/styles';
import jwt from 'jsonwebtoken';
import withRedux from 'next-redux-wrapper';
import App, {
Container,
} from 'next/app';
import Head from 'next/head';
import React from 'react';
import { Provider } from 'react-redux';
import makeStore from '../reducers';
import mainTheme from '../themes/main-theme';
import getSessIDFromCookies from '../utils/get-sessid-from-cookies';
import getLanguageFromCookies from '../utils/get-language-from-cookies';
import getUserTokenFromCookies from '../utils/get-user-token-from-cookies';
import removeFbHash from '../utils/remove-fb-hash';
import withApolloClient from '../lib/with-apollo-client'
import { ApolloProvider } from 'react-apollo'
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let userToken;
let sessID;
let language;
if (ctx.isServer) {
ctx.store.dispatch({ type: 'UPDATEIP', payload: ctx.req.headers['x-real-ip'] });
userToken = getUserTokenFromCookies(ctx.req);
sessID = getSessIDFromCookies(ctx.req);
language = getLanguageFromCookies(ctx.req);
const dictionary = require(`../dictionaries/${language}`);
ctx.store.dispatch({ type: 'SETLANGUAGE', payload: dictionary });
if(ctx.res) {
if(ctx.res.locals) {
if(!ctx.res.locals.authenticated) {
userToken = null;
sessID = null;
}
}
}
if (userToken && sessID) { // TBD: validate integrity of sessID
const userInfo = jwt.verify(userToken, process.env.JWT_SECRET);
ctx.store.dispatch({ type: 'ADDUSERINFO', payload: userInfo });
}
ctx.store.dispatch({ type: 'ADDSESSION', payload: sessID }); // component will be able to read from store's state when rendered
}
const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {};
return { pageProps };
}
componentDidMount() {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentNode.removeChild(jssStyles);
}
// Register serviceWorker
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/serviceWorker.js'); }
// Handle FB's ugly redirect URL hash
removeFbHash(window, document);
}
render() {
const { Component, pageProps, store, apolloClient } = this.props;
return (
<Container>
<Head>
// redacted for brevity
</Head>
<ThemeProvider theme={mainTheme}>
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
<CssBaseline />
<ApolloProvider client={apolloClient}>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</ApolloProvider>
</ThemeProvider>
</Container>
);
}
}
export default withApolloClient(withRedux(makeStore)(MyApp));
So with this setup, when I compile and run my app, it throws the following:
TypeError: Cannot read property 'allUsers' of undefined
I'm really lost! The repo is up at https://github.com/amitschandillia/proost/tree/master/web.