I have a backend with users that i want to display on my frontend folder.
In order to do that i need authorization headers to be implemented in React via Apollo Server.
I followed some instruction from here -> https://www.apollographql.com/docs/react/networking/authentication/
This is my code inside App.js
import React from 'react';
import HeroesDota from './components/HeroesDota';
import { ApolloProvider } from '#apollo/react-hooks';
import { ApolloClient } from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";
import { setContext } from 'apollo-link-context';
const httpLink = new HttpLink({
uri: "http://localhost:8000/graphql/",
});
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem('token');
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
}
}
});
const App = () => {
return (
<ApolloProvider client={client}>
<HeroesDota />
</ApolloProvider>
)};
export default App;
After i run server on localhost:3000 it says: Uncaught Error: Cannot find module 'apollo-link-context'
I installed apollo-link as dependency. I dont know why this error show up. Here is the actual picture.
package.json
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"#apollo/react-hooks": "^3.1.3",
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.4.0",
"#testing-library/user-event": "^7.2.1",
"apollo-boost": "^0.4.7",
"apollo-cache-inmemory": "^1.6.5",
"apollo-link": "^1.2.13",
"apollo-link-ws": "^1.0.19",
"bootstrap": "^4.4.1",
"graphql": "^14.5.8",
"react": "^16.12.0",
"react-apollo": "^3.1.3",
"react-bootstrap": "^1.0.0-beta.16",
"react-dom": "^16.12.0",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"react-scripts": "3.3.0",
"styled-components": "^5.0.0",
"subscriptions-transport-ws": "^0.9.16"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {}
}
You are importing it right here:
import { setContext } from 'apollo-link-context';
Please run npm i apollo-link-context to fix.
Related
I want to test a hook that uses states in its implementation, but each time I run my tests I get this error:
Error: Uncaught [Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.]
The hook is complex and I couldn't find which part may cause an issue (plus it works perfectly fine under real conditions, when running the application with npm start).
I tried to write a dummy test to see if I could figure out anything, and I found that updating a state (which I do in my hook) triggers the error.
Basically, this fails:
import { renderHook } from "#testing-library/react";
import React from "react";
it("foo test", () => {
const { result } = renderHook(() => {
const [foo, setFoo] = React.useState("foo");
setFoo("bar"); // This line is the culprit
return foo;
});
expect(result.current).toEqual("bar");
});
But this works:
import { renderHook } from "#testing-library/react";
import React from "react";
it("foo test", () => {
const { result } = renderHook(() => {
const [foo, setFoo] = React.useState("foo");
return foo;
});
expect(result.current).toEqual("foo");
});
What is the reason for this error and how can I fix it ?
Also, my package.json file:
{
"name": "agora-front",
"version": "0.1.0",
"private": true,
"dependencies": {
"#emotion/react": "^11.10.0",
"#emotion/styled": "^11.10.0",
"#mui/icons-material": "^5.8.4",
"#mui/material": "^5.9.3",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.3.0",
"#types/react": "^18.0.15",
"#types/react-dom": "^18.0.6",
"i18next": "^21.8.16",
"i18next-browser-languagedetector": "^6.1.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^11.18.3",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"typescript": "^4.7.4",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "BROWSER=none react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --verbose",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"#babel/preset-typescript": "^7.18.6",
"#types/jest": "^28.1.6",
"jest": "^28.1.3",
"prettier": "2.7.1",
"react-test-renderer": "^18.2.0"
}
}
I got tricked by the test environment and forgot React basic good practices.
Every state update should be wrapped in a condition with useEffect, otherwise render will trigger endlessly.
I followed that practice in all my React components, thus explaining why it was working fine when building the application. But I wrote my tests a bit quickly.
For my quick example, this is the correct way to do it:
import { renderHook } from "#testing-library/react";
import React from "react";
it("foo test", () => {
const { result } = renderHook(() => {
const [foo, setFoo] = React.useState("foo");
React.useEffect(() => {
setFoo("bar"); // Now it works.
}, [])
return foo;
});
expect(result.current).toEqual("bar");
});
I've got a very simple Create React App that I am trying to implement Cypress with. I initially had a different but related error that I was able to overcome. I'm not entirely sure why I would be given this type of error considering I do have the default "browserslist" key in my package.json file.
package.json
{
"name": "cypress_test",
"version": "0.1.0",
"private": true,
"engines": {
"node": "16.13.1",
"npm": "8.1.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"cypress": "cypress open",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"dependencies": {
"#cypress/react": "^5.12.4",
"#cypress/webpack-dev-server": "^1.8.4",
"#emotion/react": "^11.9.0",
"#emotion/styled": "^11.8.1",
"#fontsource/roboto": "^4.5.5",
"#mui/icons-material": "^5.6.2",
"#mui/material": "^5.6.3",
"#mui/styled-engine-sc": "^5.6.1",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^12.1.5",
"#testing-library/user-event": "^13.5.0",
"browserslist": "^4.6.3",
"cypress": "^9.6.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "5.0.1",
"sass": "^1.51.0",
"styled-components": "^5.3.5",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"#babel/core": "^7.17.9",
"#babel/preset-env": "^7.16.11",
"#cypress/webpack-preprocessor": "^5.11.1",
"babel-loader": "^8.2.5",
"eslint-plugin-cypress": "^2.12.1",
"html-webpack-plugin": "^4.5.2",
"webpack": "^5.72.0"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"overrides": [
{
"extends": [
"plugin:cypress/recommended"
],
"files": [
"cypress/**/*.js"
]
}
],
"resolutions": {
"#mui/styled-engine": "npm:#mui/styled-engine-sc#latest"
},
"jest": {
"coveragePathIgnorePatterns": [
"<rootDir>/cypress/"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
When I initially installed CRA, it used the latest version of React 18, but apparently Cypress doesn't have support for 18 yet so I downgraded React to 17. I'm wondering if there are some sort of package mismatches that I'm unaware of and aren't receiving specific errors for. As a note though, the app runs fine in the browser. Here are the other related files:
/cypress/plugins/index.js:
const findWebpack = require('find-webpack')
const webpackPreprocessor = require('#cypress/webpack-preprocessor');
const injectDevServer = require('#cypress/react/plugins/react-scripts');
module.exports = (on, config) => {
const webpackOptions = findWebpack.getWebpackOptions();
if (!webpackOptions) {
throw new Error('Could not find Webpack in this project');
}
const cleanOptions = { reactScripts: true };
findWebpack.cleanForCypress(cleanOptions, webpackOptions);
const options = {
webpackOptions,
watchOptions: {},
};
on('file:preprocessor', webpackPreprocessor(options));
injectDevServer(on, config);
return config;
};
App.spec.js:
import React from 'react';
import data from '../fixtures/data.json';
import App from '../../src/App.jsx';
describe('Test search functionality', () => {
beforeEach(() => {
cy.mount(<App />);
});
it('renders new fact when search is performed', () => {
cy.visit('http://localhost:3001')
// Type in search input
cy.get('input').type('Test');
// Click on search button
cy.get('.submit-btn').click();
// Intercept the request and return the mock data
cy
.intercept({
method: 'GET',
url: `${process.env.REACT_APP_API_ENDPOINT}/jokes/search?query=Test`
}, {
fixture: data.result[1]
})
.as('fetchFact');
// cy.wait(['#fetchFact']);
cy.get('p.copy').should('contain', data.result[1].value);
})
});
cypress.json:
{
"baseUrl": "http://localhost:3001",
"videos": false,
"component": {
"testFiles": "**/*.cy.{js,ts,jsx,tsx}",
"componentFolder": "src"
}
}
Cypress error:
Error: No browserslist config found to handle the 'browserslist' target.
See https://github.com/browserslist/browserslist#queries for possible ways to provide a config.
The recommended way is to add a 'browserslist' key to your package.json and list supported browsers (resp. node.js versions).
You can also more options via the 'target' option: 'browserslist' / 'browserslist:env' / 'browserslist:query' / 'browserslist:path-to-config' / 'browserslist:path-to-config:env'
at TARGETS.web (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/config/target.js:93:11)
at getTargetProperties (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/config/target.js:296:19)
at /Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/config/target.js:342:20
at Array.map (<anonymous>)
at getTargetsProperties (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/config/target.js:342:11)
at applyWebpackOptionsDefaults (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/config/defaults.js:142:6)
at createCompiler (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/webpack.js:77:2)
at create (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/webpack.js:134:16)
at webpack (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/webpack.js:158:32)
at f (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/index.js:63:16)
at Object.handler (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/#cypress/webpack-preprocessor/dist/index.js:148:24)
at invoke (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/run_plugins.js:22:16)
at /Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/util.js:45:14
at tryCatcher (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/bluebird/js/release/util.js:16:23)
at Function.Promise.attempt.Promise.try (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/bluebird/js/release/method.js:39:29)
at Object.wrapChildPromise (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/util.js:44:23)
at Object.wrap (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/preprocessor.js:28:8)
at execute (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/run_plugins.js:123:27)
at EventEmitter.<anonymous> (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/run_plugins.js:213:5)
at EventEmitter.emit (node:events:390:28)
at process.<anonymous> (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/util.js:19:22)
at process.emit (node:events:390:28)
I have simple functional component like below.
import React, { useState } from 'react';
import { connect } from 'react-redux';
import JoinRoomInputs from '../../../components/JoinRoomPage/JoinRoomInputs/JoinRoomInputs';
import { State } from '../../../store/states/states';
interface Props {
isRoomHost: boolean;
}
const JoinRoomContent = ({ isRoomHost }:Props) => {
const [roomIdValue, setRoomIdValue] = useState('');
const [nameValue, setNameValue] = useState('');
return (
<>
<JoinRoomInputs roomIdValue={roomIdValue} setRoomIdValue={setRoomIdValue} nameValue={nameValue} setNameValue={setNameValue} isRoomHost={isRoomHost} />
</>
);
};
const mapStateToProps = (state:State) => {
return {
...state
}
}
export default connect(mapStateToProps)(JoinRoomContent);
as you can see I have used useState hook in two lines.
But I'm getting yellow warning saying this.
src\components\JoinRoomPage\JoinRoomContent\JoinRoomContent.tsx
Line 1:17: 'useState' is defined but never used #typescript-eslint/no-unused-vars
Search for the keywords to learn more about each warning.
To ignore, add // eslint-disable-next-line to the line before.
And what is more curious is line 17 is this );
This doesn't make any sense to me.
What am I doing wrong here ?
below is my package.json
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"#reduxjs/toolkit": "^1.6.2",
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.5.0",
"#testing-library/user-event": "^7.2.1",
"#types/jest": "^24.9.1",
"#types/node": "^12.20.36",
"#types/react": "^16.14.20",
"#types/react-dom": "^16.9.14",
"#types/react-redux": "^7.1.20",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.6",
"react-router-dom": "^6.0.2",
"react-scripts": "4.0.3",
"typescript": "^4.1.6"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"typescript-plugin-css-modules": "^3.4.0"
}
}
Restart your server or kill the port with the following command:
sudo kill $(sudo lsof -t -i:PORT)
I want to convert my create react app typescript to ssr for serving dynamic meta tags so social medial crawlers can show preview. Has anyone done this, can share a sample code with all the config
this is my index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.hydrate(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
my server.ts
import express from "express";
import React from "react";
import {renderToString} from "react-dom/server";
import App from '../src/App'
import * as path from 'path';
import * as fs from 'fs'
import { getArticle } from "../src/api";
const app = express();
app.use(express.static("public"));
const PORT = process.env.PORT || 3006;
const indexPath = path.resolve(__dirname,'..','public','index.html')
const readIndexHtml = () => {
let response
fs.readFile(indexPath,'utf8',(err,html) => {
if(err) {
console.error('Error during file reading', err);
// return res.status(404).end()
throw err
}
response = html
})
return response
}
app.get('/',(req,res) => {
try {
let htmlData = readIndexHtml()
htmlData = (htmlData as string)
.replace('__META_OG_TITLE__', "title")
.replace('__META_OG_DESCRIPTION__', "description")
.replace('__META_DESCRIPTION__', "desc")
return res.send(htmlData);
} catch (error) {
console.log('erro while reading ' , error)
return res.status(404).end()
}
})
app.get('/article/:id', async(req,res) => {
let id = req.params.id
try {
let response = await getArticle(parseInt(id))
try {
let htmlData = readIndexHtml()
htmlData = (htmlData as string)
.replace('__META_OG_TITLE__', response.data['heading'])
.replace('__META_OG_DESCRIPTION__', response.data['shortDescription'])
.replace('__META_DESCRIPTION__', response.data['shortDescription'])
return res.send(htmlData);
} catch (error) {
console.log('erro while reading ' , error)
return res.status(404).end()
}
} catch (error) {
console.log('erro while fetching article ' , error)
return res.status(404).end()
}
})
app.listen(PORT, () => {
return console.log(`server is listening on ${PORT}`);
});
My Package.json
{
"name": "react-anoop-study",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^5.14.1",
"#testing-library/react": "^11.2.7",
"#testing-library/user-event": "^12.8.3",
"#types/jest": "^26.0.24",
"#types/node": "^12.20.15",
"#types/react": "^17.0.13",
"#types/react-dom": "^17.0.8",
"axios": "^0.21.1",
"jsx-runtime": "^1.2.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"react-toggle": "^4.1.2",
"typescript": "^4.3.5",
"web-vitals": "^1.1.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"#types/node": "^12.20.26",
"#types/react": "^17.0.22",
"#types/react-helmet": "^6.1.2",
"#types/react-router-dom": "^5.1.8",
"#types/react-toggle": "^4.0.3"
}
}
What are the packages and configurations I need to add to make the dynamic changes possible
My project structure
├───public
├───server
└───src
├───api
├───components
│ ├───carousel
│ ├───flexboxtitle
│ └───paper
├───pages
│ ├───about
│ ├───article
│ └───carouseldemo
└───style
├───component
└───pages
Easiest way of doing this is by migrating to next.js
https://nextjs.org/docs/migrating/from-create-react-app
I hope you are having a fantastic day.
I am using this API: https://apify.com/petrpatek/covid-19-aggregator/api, for the first time, and I am having some issues getting it to work with React. This is the file where I am making my API call:
const ApifyClient = require('apify-client');
require('dotenv').config({ path: `${__dirname}/../../.env` });
const client = new ApifyClient({
token: process.env.REACT_APP_API_TOKEN,
});
const input = {};
const getItems = async () => {
// Run the actor and wait for it to finish
const run = await client.actor('petrpatek/covid-19-aggregator').call(input);
// Fetch and print actor results from the run's dataset (if any)
console.log('Results from dataset');
const { items } = await client.dataset(run.defaultDatasetId).listItems();
// console.log(items);
items.forEach((item) => {
console.dir(item);
});
return items;
};
getItems();
// export default getItems();
Most of the above is just copy-pasted from the API docs, this file has no problems running as a standalone, if I run node apify.js, it returns the correct data as I expect:
correct data
However when I try to run it inside of a React component, like so:
import { useEffect } from 'react';
import CountryCard from '../components/countryCard';
import Header from '../components/header';
import getItems from '../APIs/apify';
const AllCountriesPage = () => {
useEffect(() => {
getItems();
}, []);
return (
<div className="allCountriesPage">
<Header />
<CountryCard className="bannerCountry" />
<p className="allCountriesText">All countries</p>
<div className="allCountriesContainer">
{/* Some kind of for loop */}
<CountryCard />
</div>
</div>
);
};
export default AllCountriesPage;
It throws the following error:
error message
At first, I thought this was just a problem with the dependencies, but I do have them installed, or the file would not be running by itself, also this is my package.js file:
{
"name": "catalogue-of-statistics",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"apify-client": "^1.2.4",
"dotenv": "^8.2.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"#babel/core": "^7.14.5",
"#babel/eslint-parser": "^7.14.5",
"#babel/plugin-syntax-jsx": "^7.14.5",
"#babel/preset-react": "^7.14.5",
"eslint": "^7.28.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"stylelint": "^13.13.1",
"stylelint-config-standard": "^21.0.0",
"stylelint-csstree-validator": "^1.9.0",
"stylelint-scss": "^3.19.0"
}
}
I see my colleague replied to you over our Discord.
For others:
You need to add mainFields: ['browser', 'main', 'module'], to your webpack config. The order is important. main needs to go before module. See https://webpack.js.org/configuration/resolve/#resolvemainfields
As Lukas was saying above, the Apify team answered my question directly in their discord, so I want to put the solution here if someone comes across it in the future.
You need to go to node_modules -> react_scripts -> config -> webpack.config.js inside the resolve: { ... } object, add this line: mainFields: ['browser', 'main', 'module'], make sure that main is before module.