I am learning React.js and got problem in a place.
I am fetching data from localhost:4000/products (i.e)
Here is my localhost:4000/products page
And I am doing the backend query in node.js
Here is the page:
const express = require('express');
const app = express();
const cors = require("cors");
const mysql = require("mysql");
app.use(cors());
const selectallquery = "SELECT * FROM users";
const db = mysql.createPool({
host: "localhost",
user: "root",
password: "Sakthi#1234",
database: "reactSql",
});
app.get("/",(req,res)=> {
res.send('Hello Sakthi')
});
app.get("/products/add", (req,res)=> {
const { name } = req.query;
console.log(name);
const insertquery = `INSERT INTO users (name) VALUES ('${name}')`;
db.query(insertquery, (err,result)=> {
if(err){
return res.send(err)
}
else{
return res.send("Successfully added...`")
}
});
});
app.get("/products", (req,res)=> {
db.query(selectallquery, (err,result)=> {
if (err){
return res.send(err)
}
else{
return res.send(result)
}
});
});
app.listen(4000,()=> {
console.log("Running on server 4000")
});
And here is my React.js page:
import React, { useState, useEffect } from 'react'
import axios from "axios";
function Login() {
const [names, setnames] = useState([])
useEffect(()=> {
axios.get("http://localhost:4000/products")
.then(res => {
if (res !== ""){
setnames([...names,res.data.name])
}
})
.catch(err => {
console.log(err)
})
},[])
return (
<div>
{
names
}
</div>
)
}
export default Login
The state names is not set with any value.
And it is not showing any values:
Its the page showing nothing :(
And Also i want to know how to make the useEffect hook not to render on first render(componentWillMount) and only to render at last(componentDidMount).
This is my console of res:
First, you need to update setnames because res.data is an array so you can not use res.data.name:
setnames(res.data)
And in return, you need to use map to show name:
{names.map((item) => (
<p key={item.id}>{item.name}</p>
))}
res.data is an array, so if you want to only keep names, you need to map on it to only store names to your state
setnames(names => [...names, ...res.data.map(({name}) => name)])
You can use useRef to set the node not to render at the first time.
Make React useEffect hook not run on initial render
Related
import React, { useState, useEffect } from "react";
import Axios from "axios";import { Link, Navigate } from "react-router-dom";
import "../assets/css/login.css";import "react-toastify/dist/ReactToastify.css";
import API from "../backend";
const Signout = () => {const [values, setValues] = useState({reDirect: false,});
const { reDirect } = values;
if (typeof window !== "undefined") {localStorage.removeItem("TWjwt");
const axiosGetCall = async () => {
try {
const res = await Axios.get(`${API}/logout`);
// enter you logic when the fetch is successful
console.log(`data here: `, res);
setValues({ ...values, reDirect: true });
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error log: `, error);
}
};
axiosGetCall();
}
return <>{reDirect === true ? <Navigate to="/" /> : <></>}</>;};
export default Signout;`
hello,
i'm trying to learn react and above code has no problem instead the code is hitting my backend api multiple times for single logout..
i have removed <React.StrictMode> but still it is hitting apis multiple times..
i have understood that when my state changes the code is running again and again..
so any solutions ?
useEffect(() => {
const axiosGetCall = async () => {
const res = await Axios.get(`${API}/logout`);
// enter you logic when the fetch is successful
console.log(`data here: `, res);
if (typeof window !== "undefined") {
localStorage.removeItem("TWjwt");
}
setValues({ ...values, reDirect: true });
};
axiosGetCall();
}, []);
OK- Issue was Solved...
Greetings I have a problem every time when I want to make an Admin REST API call to Shopify I get this problem "Error: Failed to parse session token '****' jwt expired" I see some code examples on the net I have my own custom session storage for accessToken and shop but every time when I try to call my own route from front-end and get more details about the shop I get this problem here is code example can anyone help me?
server.js
import "#babel/polyfill";
import dotenv from "dotenv";
import "isomorphic-fetch";
import createShopifyAuth, { verifyRequest } from "#shopify/koa-shopify-auth";
import Shopify, { ApiVersion } from "#shopify/shopify-api";
import Koa from "koa";
import next from "next";
import Router from "koa-router";
const helmet = require("koa-helmet");
const compress = require("koa-compress");
const cors = require("koa-cors");
const logger = require("koa-logger");
const bodyParser = require("koa-bodyparser");
import axios from "axios";
import { storeCallback, loadCallback, deleteCallback } from "./custom-session";
const sequelize = require("./database/database");
const { Shopify_custom_session_storage } = require("./../models/sequelizeModels");
// import apiRouter from "./../routers/apiRouter";
dotenv.config();
const port = parseInt(process.env.PORT, 10) || 8081;
const dev = process.env.NODE_ENV !== "production";
const app = next({
dev,
});
const handle = app.getRequestHandler();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\/|\/$/g, ""),
API_VERSION: ApiVersion.October20,
IS_EMBEDDED_APP: true,
// This should be replaced with your preferred storage strategy
SESSION_STORAGE: new Shopify.Session.CustomSessionStorage(storeCallback, loadCallback, deleteCallback)
});
sequelize.sync()
.then(() => {
app.prepare().then(async () => {
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
async afterAuth(ctx) {
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
const host = ctx.query.host;
// Getting users data from database and saving it to variable //
try {
await Shopify_custom_session_storage.findAll({
raw: true,
where:{
shop: shop
},
limit:1
});
} catch(err) {
console.log(err);
throw err;
}
// End of Getting users data from database and saving it to variable //
const response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: "/webhooks",
topic: "APP_UNINSTALLED",
webhookHandler: async (topic, shop, body) =>{
return Shopify_custom_session_storage.destroy({
where: {
shop: shop
}
})
.then(result => {
return true;
})
.catch(err => {
if(err) throw err;
return false;
});
}
});
if (!response.success) {
console.log(
`Failed to register APP_UNINSTALLED webhook: ${response.result}`
);
}
// Redirect to app with shop parameter upon auth
ctx.redirect(`/?shop=${shop}&host=${host}`);
},
})
);
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
};
router.post("/webhooks", async (ctx) => {
try {
await Shopify.Webhooks.Registry.process(ctx.req, ctx.res);
console.log(`Webhook processed, returned status code 200`);
} catch (error) {
console.log(`Failed to process webhook: ${error}`);
}
});
router.post("/graphql", verifyRequest({ returnHeader: true }), async (ctx, next) => {
await Shopify.Utils.graphqlProxy(ctx.req, ctx.res);
}
);
// Our Routes //
router.get("/getProducts", verifyRequest({ returnHeader: true }), async (ctx) => {
try{
const session = await Shopify.Utils.loadCurrentSession(ctx.req, ctx.res);
const client = new Shopify.Clients.Rest(session.shop, session.accessToken);
console.log(session);
}catch(err) {
console.log(err);
throw new Error(err);
}
});
// End of Our Routes //
router.get("(/_next/static/.*)", handleRequest); // Static content is clear
router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
router.get("(.*)", async (ctx) => {
const shop = ctx.query.shop;
try {
let user = await Shopify_custom_session_storage.findAll({
raw: true,
where:{
shop: shop
},
limit:1
});
// This shop hasn't been seen yet, go through OAuth to create a session
if (user[0].shop == undefined) {
ctx.redirect(`/auth?shop=${shop}`);
} else {
await handleRequest(ctx);
}
} catch(err) {
console.log(err);
throw err;
}
});
server.use(router.allowedMethods());
server.use(router.routes());
// Setting our installed dependecies //
server.use(bodyParser());
server.use(helmet());
server.use(cors());
server.use(compress());
server.use(logger());
// End of Setting our installed dependecies //
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
})
.catch((err) => {
if(err) throw err;
return process.exit(1);
})
_app.js
import ApolloClient from "apollo-boost";
import { ApolloProvider } from "react-apollo";
import App from "next/app";
import { AppProvider } from "#shopify/polaris";
import { Provider, useAppBridge } from "#shopify/app-bridge-react";
import { authenticatedFetch, getSessionToken } from "#shopify/app-bridge-utils";
import { Redirect } from "#shopify/app-bridge/actions";
import "#shopify/polaris/dist/styles.css";
import translations from "#shopify/polaris/locales/en.json";
import axios from 'axios';
function userLoggedInFetch(app) {
const fetchFunction = authenticatedFetch(app);
return async (uri, options) => {
const response = await fetchFunction(uri, options);
if (
response.headers.get("X-Shopify-API-Request-Failure-Reauthorize") === "1"
) {
const authUrlHeader = response.headers.get(
"X-Shopify-API-Request-Failure-Reauthorize-Url"
);
const redirect = Redirect.create(app);
redirect.dispatch(Redirect.Action.APP, authUrlHeader || `/auth`);
return null;
}
return response;
};
}
function MyProvider(props) {
const app = useAppBridge();
const client = new ApolloClient({
fetch: userLoggedInFetch(app),
fetchOptions: {
credentials: "include",
},
});
const axios_instance = axios.create();
// Intercept all requests on this Axios instance
axios_instance.interceptors.request.use(function (config) {
return getSessionToken(app) // requires a Shopify App Bridge instance
.then((token) => {
// Append your request headers with an authenticated token
config.headers["Authorization"] = `Bearer ${token}`;
return config;
});
});
const Component = props.Component;
return (
<ApolloProvider client={client}>
<Component {...props} axios_instance={axios_instance}/>
</ApolloProvider>
);
}
class MyApp extends App {
render() {
const { Component, pageProps, host } = this.props;
return (
<AppProvider i18n={translations}>
<Provider
config={{
apiKey: API_KEY,
host: host,
forceRedirect: true,
}}
>
<MyProvider Component={Component} {...pageProps} />
</Provider>
</AppProvider>
);
}
}
MyApp.getInitialProps = async ({ ctx }) => {
return {
host: ctx.query.host,
};
};
export default MyApp;
index.js
import { Heading, Page, Button } from "#shopify/polaris";
function Index(props){
async function getProducts(){
const res = await props.axios_instance.get("/products");
return res;
}
async function handleClick() {
const result = await getProducts();
console.log(result);
}
return (
<Page>
<Heading>Shopify app with Node and React </Heading>
<Button onClick={handleClick}>Get Products</Button>
</Page>
);
}
export default Index;
I found the solution for "Error: Failed to parse session token '******' jwt expired" the problem was Computer Time was not synchronized, check the computer time and synchronized it, for my example, I'm on Kali Linux and I search it how to synchronize time on Kali Linux and follow that tutorial when you finally synchronize your time restart your application server and try again. That's it so dump I lost 4 days on this.
I'm trying to pass userData with app.render, but while Server side rendering router.query is empty, although i have passed userData! Is it NextJS's bug, or am i doing something wrong?
app.js:
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
if (pathname === '/index') {
app.render(req, res, '/index', {
userData: {
id: 1,
name: 'admin'
}
})
} else {
handle(req, res, parsedUrl)
}
}).listen(3333, err => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
pages/index.js:
import { useRouter } from 'next/router'
export default () => {
const router = useRouter();
const { query } = router;
return (
<div>
Query: {JSON.stringify(query)}
</div>
);
};
If getInitialProps is absent, Next.js will statically optimize your
page automatically by prerendering it to static HTML. During
prerendering, the router's query object will be empty since we do not
have query information to provide during this phase. Any query values
will be populated client side after hydration.
You can access your query using getInitialProps.
with useRouter:
import { useRouter } from 'next/router'
const Index = () => {
const router = useRouter();
const { query } = router;
return (
<div>
Query: {JSON.stringify(query)}
</div>
);
};
Index.getInitialProps = async () => {
return {};
};
export default Index
with a class component:
import React from 'react'
class Index extends React.Component {
static async getInitialProps (context) {
let query = context.query;
return {query}
}
render() {
let {query} = this.props
return (
<div>
Query: {JSON.stringify(query)}
</div>
);
}
}
export default Index
Or if you prefer a functional component :
const Index = (props) => (
<div>
Query: {JSON.stringify(props.query)}
</div>
)
Index.getInitialProps = async ( context ) => {
let query = context.query;
return {query}
}
export default Index
Please note that obviously this works with /index but not with /
I think it's as simple as adding a return statement before app.render to prevent the rest of the code from executing.
if (pathname === '/index') {
return app.render(req, res, '/index', {
userData: {
id: 1,
name: 'admin'
}
})
} else {
handle(req, res, parsedUrl)
}
I am trying to pass a socket.io instance into Express Routes. Currently I am setting up the socket.io server as shown on their documentation. To pass the object into the routes I am using app.set('io', io) and then in the route const io = req.app.get('io') within the route. After getting the io object, I am simply emitting to all listening users. This works for the first request but then the second time the same request is made, two events get sent to every client. The third request emits the data three times and so on.
// App.js file
// Server imports
const app = require('express')(),
http = require('http').Server(app),
io = require('socket.io')(http),
session = require('express-session');
// Add socket.io to req for use in latter requests
app.set('io', io);
io.on('connection', (socket) => {
console.log('User has connected to socket.io');
socket.on('disconnect', () => {
console.log('User has disconnected');
});
});
// Route Setups
app.use('/api', require('./routes'));
http.listen(process.env.PORT, () => {
console.log(`Server running on port: ${process.env.PORT}`);
});
// Route index.js
const router = require('express').Router();
router.use('/project', require('./project/project'));
module.exports = router;
// Project Routes
const router = require('express').Router(),
Project = require('../../models/project');
// Route for creating new Projects
router.post('/', (req, res, next) => {
Project.createProject(req.body.item, (err, doc) => {
if(err) return next(err);
res.json({_id: doc._id, projectName: doc.projectName});
const io = req.app.get('io');
io.emit('project', {project: {
_id: doc._id,
client: doc.client,
jobId: doc.jobId,
projectName: doc.projectName,
eventDate: doc.eventDate,
dateModified: doc.dateModified,
eventLogo: doc.eventLogo
}});
})
});
// index.js
// Import React Standard components
// Import and setup BrowserRouter
import App from './components/App';
import io from 'socket.io-client';
const socket = io('http://192.168.1.2:8080');
ReactDOM.render(
<BrowserRouter>
<App socket={socket}/>
</BrowserRouter>
, document.getElementById('root'));
// Front End React File for displaying projects - App.js
// I cut down on some of the code to keep it simple.
import React, { Component } from 'react';
import NewProject from './NewProject';
export default class Projects extends Component {
state = {
projects: []
newProject: false
}
closeWindow = () => {
// Sets the state for new Project to true or false to show or hide the component
}
componentDidMount = () => {
// Fires mutiple times for each request made to update project or create new project
this.props.socket.on('project', ({project, index}) => {
console.log("DATA RECIEVED", project, index);
const projects = this.state.projects;
// If a project and index is sent, update an excising project
if(project !== undefined && index !== undefined) {
console.log('Project to ypdate: ',projects[index])
projects[index] = Object.keys(projects[index]).reduce((acc, key) => {
// Update all keys passed down from the server
}, {});
// If just a project is sent, add a new project
} else if(project !== undefined && index === undefined) {
projects.push(project);
// If just an index is sent, remove the project
} else if(index !== undefined) {
const projectIndex = this.props.projects.findIndex((item) => {
if(item._id === index) return true;
return null;
});
projects.splice(projectIndex, 1);
}
return this.setState({projects});
});
}
render() {
return [
this.state.newProject && <NewProject key="0" closeWindow={this.closeWindow} />
<main key="1">
// Display the projects
<button type="button" onClick={this.closeWindow}>New Project</button>
</main>
]
}
// Front End React File for Creating New Project
// NewProject.js
import React, { Component } from 'react';
export default class CreateProject extends Component {
state = {
client: '',
projectName: '',
jobId: '',
eventDate: '',
eventLogo: '',
completeForm: false
}
createProject = e => {
if(!this.state.completeForm) return;
fetch('/api/asset/project', {
method: 'POST',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(this.state)
})
.then(res => res.json())
.then(res => {
return this.props.closeWindow();
})
.catch(error => {// Handle Error})
}
render() {
return (
<div className="popup">
<form onSubmit={this.createProject}>
// All inputs for form.
</form>
</div>
)
}
}
I was expecting each user to revive the data emitted once but depending on how many times the request is made, they get the data that many times.
Thank you so much!!
Please check how many times the app.js file is called. If it is called multiple times there are multiple events of io.on("connection"..
Hence the user receives data multiple times.
What worked for me was adding this to the Component Will Unmount
componentWillUnmount = () => {
this.props.socket.off('project');
}
I did not realize the event listener was not detaching itself when the component unmounted.
I need to pass a search query from my front end (in React) to my back end (Express) so that my Twitter API route will grab the correct data. Here is where I'm hitting the Twitter API. I was just playing around with a req.query to check out JSON so I know that part needs to be removed.
tweets.js
var express = require('express');
var router = express.Router();
const bodyParser = require('body-parser');
const Twit = require('twit');
const config = require('./config');
var T = new Twit(config);
/* GET users listing. */
router.get('/', function(req, res, next) {
let ticker = req.query.ticker;
T.get('search/tweets', { q: ticker })
.then(function(result) {
var tweets = result.data;
console.log(tweets);
res.send({tweets});
})
.catch(function(err) {
console.log('caught error', err.stack)
res.send({ error: err })
})
})
module.exports = router;
Also note route is set up like this in express
app.use('/tweets', tweets);
And here is my front end in React (ignoring the actual search component for now). Just confused as to how I would send a search query
import React, { Component } from 'react';
import '../App.css';
const filterData = (tweet) => {
return ((!tweet.retweeted) && !(tweet.text.includes('RT #') && ((tweet.in_reply_to_status_id) === null)));
};
class Twitter extends Component {
constructor(props) {
super(props);
this.state = {
tweets:[],
}
}
componentDidMount() {
this.getData("GOOG");
}
getData = (query) => {
fetch('/tweets?ticker='+query)
.then(res => res.json())
.then(data => data.statuses)
.then(statuses => statuses.filter(filterData))
.then(results => this.setState({tweets:results}))
}
render() {
return (
<div className="App">
<h1>Tweets About </h1>
{this.state.tweets.map(tweet =>
<div key={tweet.id}>{tweet.text}</div>
)}
</div>
);
}
}
export default Twitter;
The issue is here in this line.
Wrong one
fetch('/tweets?ticker={query)') <-- this is wrong
Correct one
const filterData = (tweet) => {
return ((!tweet.retweeted) && !(tweet.text.includes('RT #') && ((tweet.in_reply_to_status_id) === null)));
};
class Twitter extends Component {
constructor(props) {
super(props);
this.state = {
tweets:[],
}
}
componentDidMount() {
this.getData("GOOG");
}
getData = (query) => {
fetch(`http://localhost:3001/tweets?ticker=${query}`, {method: 'GET', headers: {"Content-Type": "application/json", "Access-Control-Allow-Origin": "*"}})
.then(res => res.json())
.then(data => data.statuses)
.then(statuses => statuses.filter(filterData))
.then(results => this.setState({tweets:results}))
}
renderTweets(){
if(this.state.tweets){
this.state.tweets.map(tweet =>
<div key={tweet.id}>{tweet.text}</div>
)
}
}
render() {
return (
<div className="App">
<h1>Tweets About </h1>
{this.state.tweets ? this.renderTweets(): ''}
</div>
);
}
}
export default Twitter;
Use template literals
fetch(`/tweets?ticker=${query}`)
OR
use normal string
fetch('/tweets?ticker='+query)
Check here for more details on how template literals works. Your code should be fine now.