How to set up Hardhat with Typescript support along with React & Typescript? - reactjs

I was wondering if anyone had create a contract in hardhat and generated & compiled the contract with typechain. Taking the compiled contract and used it in a react app.
I am able to write a contract & generate the necessary files fine using npx hardhat and choosing the option with typescript. npx hardhat compile generates the necessary json and typescript stubbings. Now I am lost on how to bring that into a React app. I also do not want to deploy the contract in the smart contract. Assume the smart contract is deployed (locally is fine). Knowing this, is it possible to use the smart contract in react with type safety.

There are many well written articles on the web about combining react with web3 stuff: https://dev.to/rounakbanik/building-a-web3-frontend-with-react-340c
But basically you have to compile your smart contract to an abi file that can be read by your react webapp.
There are libraries for that (also mentioned in most articles / tutorials)
Hope this helps ;)

In hardhat projects layout, we keep the hardhat stuff in its own directory, maybe named contracts. When you created the .json files, take that json file and copy it in a client directory, maybe create a lib folder. You should have this file
client/lin/MyContract.json
to create the contract, we need to get the abi from json data.
// your directory path might be different
// in next.js it is easy importing from .json, you have to handle it differently in webpack
import abi from '../lib/MyContract.json'
Once you get the abi, you used it as abi.abi.
to create a contract write a function
const getEthereumContract = () => {
// instead of ethereum u might be using a different provider
const provider = new ethers.providers.Web3Provider(ethereum)
const signer = provider.getSigner()
// this is the contract
const MyContract = new ethers.Contract(
contractAddress,
abi.abi,
signer,
)
return MyContract
}
You get the contract address when you run the deploy script.
const main = async () => {
const transactionFactory = await hre.ethers.getContractFactory('Transactions')
const transactionContract = await transactionFactory.deploy()
await transactionContract.deployed()
// GET THIS CONTRACT ADDRESS
console.log('Transactions deployed to:', transactionContract.address)
}
;(async () => {
try {
await main()
process.exit(0)
} catch (error) {
console.error(error)
process.exit(1)
}
})()
Finally you should have this to create the contract:

Related

process is undefined in React

I am building a simple React app that generates a QR code from data. I am interested in inspecting the memory usage when the QR code is generated. I am using the built process.memoryUsage() function but the app throws and exception
Uncaught TypeError: process__WEBPACK_IMPORTED_MODULE_1__.process is undefined
I have tested some different solution, i tried to rollback the react script version to "4.0.3" i tried to download the npm polyfill webpack but there is no success.
I am currently using these imports
import React, { useState, useEffect } from 'react';
import process from 'process';
import './App.css';
const QRCode = require('qrcode');
The function looks like this
let stringData = JSON.stringify(qrData);
console.log("Number of chars in data" + " " + stringData.length);
QRCode.toDataURL(stringData, function (err, url) {
if(err) return console.log("error occured")
//window.location.href = url;
})
const used = process.memoryUsage();
for (let key in used) {
console.log(`${key} ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`);
}
}
process is a Node.js API and is not available in the browser where your React app is running, which is why you see that error. If there is an available global process object, it is being polyfilled by something in your build tools, and will not have the memoryUsage method.
There is no equivalent API for the browser, but some related APIs do exist. Note that this is an evolving space and some are non-standard, so be sure to read both the spec and documentation before considering any usage:
Device Memory API (MDN)
Performance.memory (MDN)
You are using a built in nodejs package in a react app. Node executes on the server and has access to system level resources. React runs in the browser and does not. See this article for some tips measuring performance in React.

How to test custom React-query hook that is based on Firebase methods?

I came across react-query-firebase which are hooks that are built on React-query for firebase.
I also found library called mock service worker https://mswjs.io/ however it is based on REST and GraphQL.
Here is an example code how I would use these hooks:
import React from "react";
import { useFirestoreDocument } from "#react-query-firebase/firestore";
import {
doc
} from "firebase/firestore";
import { firestore } from "../firebase";
function GetUser() {
const id = "pW5CizOJOpXezr5lGGshDmKdVpP3";
const ref = doc(firestore, "users", id);
const user = useFirestoreDocument(["users", id], ref);
return (
<div>
{user.isLoading && <div>Loading...</div>}
{user.data && <div>{user.data.data()?.name}</div>}
</div>
);
}
export default GetUser;
I am new to testing and I have no idea how would I have to execute this test, since I am mocking requests can I use random url anyways or does it have to be firebase related methods?
react-query-firebase library is an abstraction over Firebase that encapsulates resource paths (it's an SDK, I believe). Since the paths (URLs) are abstracted from, you have at least two options for how to mock requests issued by such libraries.
Option 1: Use explicit paths
Although the exact resource paths are hidden away, requests still reference existing absolute paths. You can observe those in the "Network" tab of your browser or by enabling a simple request introspection with msw:
// my.test.js
import { setupServer } from 'msw/node'
const server = setupServer(/* no handlers */)
beforeAll(() => server.listen())
afterAll(() => server.close())
Since we're using setupServer with no handlers, all requests that happen in my.test.js will be printed as warnings to stderr. You can observe those warnings to see what resource paths your SDK requests.
The benefit of using an SDK is that it guarantees you a certain resource path structure. Most likely, you will be able to replicate that structure in your mocks:
// src/mocks.js
import { rest } from 'msw'
export const handlers = [
rest.get('https://some-resource.:checksum.firebase.app/path', (req, res, ctx) => res(ctx.text('hello)))
]
Utilize dynamic path segments like :checksum to match a broader range of paths.
The downside of this approach is that your mock definition becomes dependent on the SDK internal details (resource paths). Any updates to the SDK may break your mocks, since they may update the path structure internally without denoting it as a breaking change (abstracted paths are not public API).
Option 2: Spy on the SDK
Alternatively, you can spy on the SDK you're using. An example of such a spy would be using jest.spyOn on the react-query-firebase directly:
// my.test.js
import * as reactQueryFirebase from 'react-query-firebase'
it('creates a user', () => {
jest.spyOn(reactQueryFirebase, 'SOME_METHOD_NAME')
.mockReturnValue(/* mock */)
})
The downside of this method is that you're stubbing the functions from a third-party library, which means your code under test never calls those functions. This decreases the reliability of such a test, and you should, generally, avoid resorting to this approach.
I do recommend you research Firebase, since major SDK providers often have guidelines on mocking their API. Often such a guidance would include using a dedicated third-party package authored by the SDK provider that allows mocking their internal resources.

React -- getting ".map is not a function" on PRODUCTION build, but not on regular dev build?

I can't seem to debug this... not sure what's wrong.
This is a React front-end communicating using AXIOS to a Java/MySQL backend. Axios is making CRUD requests over localhost to fetch/update data.
When I run NPM START (development - port 3000) for my React application, it runs fine. However, when I run NPM RUN BUILD and then serve the production build (port 5000), I am getting the following error messages in the console:
Uncaught (in promise) TypeError: this.state.reportData.map is not a function
at t.value (TotalsPerCustomer.js:378)
at Oi (react-dom.production.min.js:3785)
at Ni (react-dom.production.min.js:3776)
at Ri (react-dom.production.min.js:3960)
at Va (react-dom.production.min.js:5514)
at Qa (react-dom.production.min.js:5536)
at Ou (react-dom.production.min.js:5958)
at Pu (react-dom.production.min.js:5925)
at ku (react-dom.production.min.js:5860)
at Ja (react-dom.production.min.js:5787)
I faced this ".map is not a function" previously when I wasn't properly using an ARRAY - but I know this isn't causing the issue now since it works fine on development (Port 3000).
I've tried to do some research on why this is occurring but haven't found any clear answers.
I have added "localhost:5000" to the allowed Origins for CORS in Java back end:
package com.example.groupproject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#SpringBootApplication
public class GroupProjectApplication {
public static void main(String[] args) {
SpringApplication.run(GroupProjectApplication.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000","http://localhost:3001","http://localhost:5000");
}
};
}
}
I think I need to understand better what is occurring when a production build is created - I know it creates an minified version of the code -- does this mean that if I have functions named the same thing in different React components then it will create an issue?
Do I need to add the axios dependency somewhere in my WebPack folder? Or is there a different dependency or something missing in my WebPack?
See below screenshot of the console:
I don't really know how to begin debugging using these console errors - can someone shed some light on this?
My apologies for being a little clueless on this production build - any help is much appreciated.
Thanks!
This happen to me as well. First I tried to resolve as it is problem with Array and then finally realized that in reality it is not - because front end (port 5000, production build) lost connection with back end (port 8080) when building for production, hence array was empty.
So this is how I resolved it:
created .env file in root of my React project:
REACT_APP_API_URL_PROD=http://xxx.xxx.xxx.xxx:8080
REACT_APP_API_URL_TEST=http://xxx.xxx.xxx.xxx:8080
REACT_APP_API_URL_DEV=http://localhost:8080
and then in requests.js file (code snippet)
import axios from 'axios';
import endpoints from './endpoints';
if (process.env.NODE_ENV === 'production') {
axios.defaults.baseURL = process.env.REACT_APP_API_URL_PROD;
} else if (process.env.NODE_ENV === 'test') {
axios.defaults.baseURL = process.env.REACT_APP_API_URL_TEST;
} else {
axios.defaults.baseURL = process.env.REACT_APP_API_URL_DEV;
}
export const getRequest = async url => axios.get(url);
export const get = (type, params, options = null) => dispatch => {
const fn = endpoints[type];
axios.defaults.headers.common = {'Authorization': `Bearer ${localStorage.getItem('token')}`};
axios.get(fn(params), options)
.then(response => {
dispatch({
type: type,
payload: response.data
});
});
};
Now, why this is late answer for you, might happen to someone in the future to lose few hours trying to resolve this.
After this, static pages were properly served with 'serve -s build' as well as with Apache HTTP server, and I guess it could be served with any other server.
Please read this for further info.
marked as duplicate of this question:
data.map is not a function
In general, when getting ".map is not a function", this means that you aren't giving an array to map. Only array types can be mapped. So if needed, set the initial state as an empty array (then fetch data, set state, etc.). Bear in mind that if you are mapping certain keys into your page, you may need to set the initial empty array with a 'blank' object, with empty or null values for those keys.
Thanks to those who helped answer this question initially.

What is the best way to structure REST backend API calls with React?

Currently me and some colleagues are building a full stack web application, using React as our frontend framework. In this application, we need to perform CRUD operations on multiple resources, therefore multiple pages.
In my previous experience, I found tutorials/courses that put API calls in a services folder. Here's a simple example.
However, I realized this approach doesn't address loading/error states. So, I tried to come up with a solution using hooks, following another example I found: code.
This worked well for a feature I implemented, but I don't know how extensible it can be.
My question is, what is the better approach? Is there another one I didn't mention?
Reactjs is a library not a framework like Angular, there no one single approach how to handle your project structure. There are many alternatives, try to follow the good practices; if you are developing a big project that needs to scale use Redux as state management library, for me for a simple React project, we make folder called services and in an index file we prepare all our services :
/* root services ⚓️ .. */
import axios from 'axios';
const API_URL = 'http://yourapi.com/api/';
const headers = { 'Content-Type': 'application/json' };
const add = (data) => axios.post(`${API_URL}/form`, data, { headers });
const getData = () => axios.get(`${API_URL}/hotels`, { headers });
etc ...
export {
add,
getData
};
And for the call into Components
import { serviceName } from '../services/index';
serviceName({/*params if it's necessary */ })
.then(data => {
//---Get your Data
})
.catch(err => {
//---Handle your Api call error
});

test database for react-native app development

I'm in the early stages of developing an app with react-native, and I need a DB implementation for for testing and development. I thought that the obvious choice would be to use simple JSON files included with the source, but the only way I see to load JSON files requires that you know the file name ahead of time. This means that the following does not work:
getTable = (tableName) => require('./table-' + tableName + '.json') // ERROR!
I cannot find a simple way to load files at runtime.
What is the proper way to add test data to a react-native app?
I cannot find a simple way to load files at runtime.
In node you can use import() though I'm not sure if this is available in react-native. The syntax would be something like:
async function getTable(tableName){
const fileName = `./table-${tableName}.json`
try {
const file = await import(fileName)
} catch(err){
console.log(err
}
}
though like I said I do not know if this is available in react-natives javascript environment so ymmv
Unfortunately dynamic import not supported by react-native but there is a way so to do this
import tableName1 from './table/tableName1.json';
import tableName2 from './table/tableName2.json';
then create own object like
const tables = {
tableName1,
tableName2,
};
after that, you can access the table through bracket notation like
getTable = (tableName) => tables[tableName];

Resources