How to reassign a ref to a component in App.js - reactjs

I am new to react and i am trying to get the reference value from DisplayMapClass bellow is the code. The main objective is to get the MAP object from the bellow code.
DisplayMapClass.js
import * as React from 'react';
export class DisplayMapClass extends React.Component {
mapRef = React.createRef();
state = {
map: null
};
componentDidMount() {
const H = window.H;
const platform = new H.service.Platform({
apikey: "{enter api key}"
});
const defaultLayers = platform.createDefaultLayers();
const map = new H.Map(
this.mapRef.current,
defaultLayers.vector.normal.map,
{
center: { lat: 50, lng: 5 },
zoom: 4,
pixelRatio: window.devicePixelRatio || 1
}
);
const behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
const ui = H.ui.UI.createDefault(map, defaultLayers);
this.setState({ map });
}
componentWillUnmount() {
this.state.map.dispose();
}
render() {
return (
<div ref={this.mapRef} style={{ height: "500px" }} />
);
}
}
When I reassign the ref the whole page breaks so i don't know what i am doing wrong.
const map = <DisplayMapClass ref={"newRef"}/>
Bellow is the code for App.js
App.js
import logo from './logo.svg';
import './App.css';
import React, { useEffect, useState } from 'react';
import axios from 'axios'
import Button from '#mui/material/Button';
import TextField from '#mui/material/TextField';
import {BounceLoader, BarLoader, BeatLoader} from 'react-spinners'
import {DisplayMapClass} from './DisplayMapClass';
const H = window.H;
function App() {
const [isLoading, setLoading] = useState(false)
const map = <DisplayMapClass ref={"newRef"}/>
const asyncFunc = async () => {
setLoading(true);
const response = await fetch('http://000.000.000.000:000/test/8.8.8.8' );
const data = await response.json();
for(var x in data){
addMarker(map, x["lat"], x["lng"])
}
setLoading(false)
}
const addMarker = (map, x, y) => {
var marker = new H.map.Marker({"lat": x, "lng": y})
map.addObject(marker);
}
return (
<div className="App">
{ isLoading ?
<header className="App-header">
<p>please type an ip address and when done press the button</p>
<TextField
sx=
{
{
input:
{
color: 'white'
}, root:
{
color: 'white'
}, floatingLabelFocusStyle:
{
color: "white"
}
}
}
id="ipTextArea" label="Enter an IP address" variant="filled"
/>
<Button onClick={asyncFunc} variant="outlined">Map My Stalkers</Button>
<BarLoader/>
</header>
:
<header className="App-header">
<p>please type an ip address and when done press the button</p>
<TextField
sx=
{
{
input:
{
color: 'white'
}, root:
{
color: 'white'
}, floatingLabelFocusStyle:
{
color: "white"
}
}
}
id="ipTextArea" label="Enter an IP address" variant="filled"
/>
<Button onClick={asyncFunc} variant="outlined">Map My Stalkers</Button>
</header>
}
<p> <br /> </p>
<div> {map} </div>
</div>
);
}
export default App;

Related

Wagmi NextJS App is sending a transaction without a button click

I have the following NextJS App (using reactjs, ethers.js, wagmi and connectkit), that just sends Eth from one connected Metamask Wallet to another Metamask Wallet, both of which I have access to. The problem is that before clicking the send button, it is automatically sending the transaction. I did a workaround where I have a boolean (hasClicked) that stops the transaction from taking place, but it seems a bit hamfisted. I am going off of the sendTransaction found here: https://wagmi.sh/examples/send-transaction
Below is my code:
// comps/transaction.tsx
import * as React from 'react';
import { useDebounce } from 'use-debounce';
import { usePrepareSendTransaction, useSendTransaction, useWaitForTransaction } from 'wagmi'
import { utils } from 'ethers';
export function SendTransaction() {
let hasClicked = false;
const [to, setTo] = React.useState('');
const [debouncedTo] = useDebounce(to, 500);
const [amount, setAmount] = React.useState('');
const [debouncedAmount] = useDebounce(amount, 500);
const { config } = usePrepareSendTransaction({
request: {
to: to,
value: (amount && hasClicked) ? utils.parseEther(amount) : undefined,
},
});
const { data, sendTransaction } = useSendTransaction(config);
const { isLoading, isSuccess } = useWaitForTransaction({
hash: data?.hash,
});
return (
<div>
<input
aria-label="Recipient"
onChange={(e) => {
console.log("Address Set:", e.target.value);
hasClicked = false;
e.preventDefault();
setTo(e.target.value);
}}
placeholder="0xA0Cf…251e"
value={to}
/>
<input
aria-label="Amount (ether)"
onChange={(e) => {
console.log("Amount Set:", e.target.value);
e.preventDefault();
hasClicked = false;
setAmount(e.target.value);
}}
placeholder="0.05"
value={amount}
/>
<button
onClick={(e) => {
e.preventDefault();
hasClicked = true;
sendTransaction?.();
}}
disabled={isLoading}>
{isLoading ? 'Sending...' : 'Send'}
</button>
{isSuccess && (
<div>
Successfully sent {amount} ether to {to}
<div>
<a href={`https://etherscan.io/tx/${data?.hash}`}>Etherscan</a>
</div>
</div>
)}
</div>
)
}
// pages/_app.tsx
import '../styles/globals.css';
import type { AppProps } from 'next/app';
import { WagmiConfig, createClient, useAccount, useConnect, useDisconnect, goerli } from 'wagmi';
import { mainnet, polygon, optimism, arbitrum } from 'wagmi/chains';
import { ConnectKitProvider, getDefaultClient } from 'connectkit';
import { SendTransaction } from '../comps/transaction';
const client = createClient(
getDefaultClient({
appName: 'ConnectKit Next.js demo',
//infuraId: process.env.NEXT_PUBLIC_INFURA_ID,
//alchemyId: process.env.NEXT_PUBLIC_ALCHEMY_ID,
chains: [mainnet, polygon, optimism, arbitrum, goerli],
})
);
function MyApp({ Component, pageProps }: AppProps) {
const { isConnected } = useAccount();
const loading = (
<div>
<SendTransaction />
</div>
);
return (
<WagmiConfig client={client}>
<ConnectKitProvider>
{isConnected ? (loading) : (<Component {...pageProps} />)}
</ConnectKitProvider>
</WagmiConfig>
);
}
export default MyApp;
// pages/index.tsx
import type { NextPage } from 'next';
import { ConnectKitButton } from 'connectkit';
const Home: NextPage = () => {
return (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100vh',
}}
>
<ConnectKitButton />
</div>
);
};
export default Home;
Again, without the hasClicked, the transaction is automatically sent.
I would also like to validate the constants "to" and "amount" before the transaction is sent, as this would be best practice, and would also like the "Send" button disabled until to and amount are validated as correct.
I am positive there must be a better way of doing this, but I am just not sure what that is.

What is going wrong, so that it is an empty page

I would like to set up a language selector at the component Header.jsx so that when clicking on the language switch, the content of MainPage.js would change to the selected language.
the files sturcture like this
project / public / locales/ en / translation.json
project/src/i18n.js
project/src/MainPage/mainPage.js
project/Resources/Component/Header.jsx
project/Resources/Component/Footer.jsx
{
"title": "Welcome to react using react-i18next",
"description": {
"part1": "To get started, edit <1>src/App.js</1> and save to reload.",
"part2": "Switch language between English and Chinese using buttons above."
},
"agreement": "Consent",
"agree": "Agree",
"disagree":"Disagree"
}
project / public / locales/ tw / translation.json
{
"title": "歡迎使用 react-i18next",
"description": {
"part1": "要開始,請編輯 src/App.js 並保存以重新加載。",
"part2": "使用上面的按鈕在英語和中文之間切換語言。"
},
"agreement": "同意書",
"agree": "我同意'",
"disagree":"我拒絕"
}
Here is the coding at MainPage.js
import React, { useState, useEffect, Component , Suspense, useCallback} from "react";
import Header from "../Resources/Components/Header";
import Footer from "../Resources/Components/Footer";
import { useTranslation, withTranslation, Trans } from 'react-i18next';
import {MainPageContext, useMainPageContext } from "../Resources/Hooks/mainPageContext";
import "./MainPage.css";
class LegacyWelcomeClass extends Component {
render() {
const { t } = this.props;
return <h2>{t('title')}</h2>;
}
}
const Welcome = withTranslation()(LegacyWelcomeClass);
const MainPage = () => {
const { t, i18n } = useTranslation();
const context = useMainPageContext();
const changeLanguage = useCallback((lng) => {
i18n.changeLanguage(lng);
}, [i18n]);
let language=[0,1];
const [introductionPage, setIntroductionPage] = useState(0);
console.log("language is", changeLanguage('en'))
//const [language, setLanguage]= useState(0);
//below is the script of the test description. 隨時可以加入新array做新language。
const renderLanguageSwitch = () => {
return [t('testStart'), t('testAgreement')];
};
const renderButtonSwitch = () => {
return [t('agree'), t('disagree')];
};
return (
<div className="MainPage">
<Trans i18nKey="title">
<h2>{t('title')}</h2>
</Trans>
<Header />
<div
style={{
width: "100%",
height: "100vh",
backgroundColor: "#F5821F",
margin: "0",
}}
>
{introductionPage === 0 && (
<button
className="testStartBox"
onClick={() => {
setIntroductionPage(1);
}}
>
t('agree'), t('disagree')
</button>
)}
{introductionPage !== 0 && (
<div>
<div
className="testDescriptionBox"
onClick={() => {
setIntroductionPage(introductionPage + 1);
}}
>
t('description')
</div>
<div className="testAgreement">
</div>
</div>
)}
<div
className="buttonWrapper"
style={{ display: introductionPage === 1 ? "" : "none" }}
>
<button onClick={() => {
setIntroductionPage(introductionPage + 1);
}}> t('description')</button>
<button onClick={() => {
setIntroductionPage(0);
}}>{t('agreement')}</button>
</div>
</div>{" "}
<Footer />
</div>
);
};
export default MainPage;
Here is the coding Header.jsx
import React , {useCallback}from "react";
import { useMainPageContext } from "../Hooks/mainPageContext";
import { useTranslation } from 'react-i18next';
import { Trans } from "react-i18next";
import i18n from '../../i18n'
export const LanguageContext = React.createContext();
const Header = () => {
const { t, i18n } = useTranslation();
const context = useMainPageContext();
const {
language,
onSetLanguage,
} = context;
const changeLanguage = useCallback((lng) => {
i18n.changeLanguage(lng);
}, [i18n]);
const toggle = lng => i18n.changeLanguage(lng);
if (this.props.event){
return (
<div className="header">
<h1
style={{
display: "flex",
flexFlow:"row",
alignItems:"center",
width: "calc(100% - 10%)",
height: "4vh",
backgroundColor: "white",
paddingTop:"0",
padding: "2.5%",
paddingLeft: "5%",
paddingRight: "5%",
justifyContent:"space-between"
}}
>
<div style={{display:"flex", color: "#F5821F",}}>
<img src={require("../Images/cmghLogo.png")} style={{width:"50%", height:"7.5%", marginTop:"0vh"}} alt="中心"/>
<div style={{ top: "0", margin: "0vh", marginLeft:"2vw", width:" 100%", fontSize:"3vw"}}>中心</div>
</div>
<div>
<header>
<button onClick={() => toggle(this.props.event)}>English/</button>
<button onClick={() => toggle(this.props.event)}>TW</button>
</header>
</div>
</h1>
</div>
);
}
}
export default Header;
Here is the coding of i18n.js
import { createInstance } from 'i18next';
import { initReactI18next } from 'react-i18next';
const i18n = createInstance({
fallbackLng: 'en',
debug: true,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
resources: {
en: {
translation: {
hello: 'Hello from other i18n instance',
},
},
tw: {
translation: {
hello: 'Hallo aus einer anderen i18n Instanz',
},
},
},
});
i18n.use(initReactI18next).init();
export default i18n;

React router renders differently when using useNavigate vs typing in url directly or refreshing

New to using react-router, especially react-router v6.
I'm using react-flow in conjunction with react render and one of my routes is rendering in different ways depending on whether I navigate to the url directly (the way I would expect it render) vs if I navigate to it using the in-built workflow, the rendering is a little wonky.
Everything right now is on localhost
Code is below as is a gif.
Gif of activity
Components
Flow.jsx
import React, {useCallback} from 'react';
import ReactFlow, { useNodesState, useEdgesState, addEdge, Controls, ControlButton } from 'react-flow-renderer';
import { AiOutlineSubnode } from 'react-icons/ai';
import '../App.css';
const snapGrid = [20, 20];
const Flow = (props) => {
const windowHeight = window.innerHeight;
const divStyle = {
width: '100%',
height: windowHeight * 0.9
}
const [nodes, setNodes, onNodesChange] = useNodesState(props.nodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(props.edges);
const onConnect = (params) => setEdges((eds) => addEdge(params, eds));
const addNode = useCallback(() => {
setNodes((n) => {
var newId
if (n.length > 0) {
newId = n[n.length - 1].id + 1
}
else {
newId = 1
}
return ([...n, {
id: newId,
type: "default",
position: { x: 20, y: 10 },
data: { label: "Enter title..." }
}])
})
}, [setNodes])
return (
<div style={divStyle}>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
snapToGrid={true}
snapGrid={snapGrid}
defaultZoom={1.5}
fitView
attributionPosition="bottom-left"
>
<Controls>
<ControlButton onClick={addNode}>
<AiOutlineSubnode />
</ControlButton>
</Controls>
</ReactFlow>
</div>
);
};
export default Flow
Nav.jsx
import React from 'react'
import Button from '#mui/material/Button'
export const Nav = (props) => {
const windowHeight = window.innerHeight;
const divStyle = {
width: '100%',
height: windowHeight*0.9
}
return (
<div style={divStyle}>
<div>
<Button variant='contained'
onClick={()=>{
alert("Nav")
props.nav()
}}
>
Send
</Button>
</div>
</div>
)
}
React Router
Router
import React from 'react';
import {
createBrowserRouter,
RouterProvider
} from "react-router-dom";
import RootRoute from './routes/RootRoute';
import IndexRoute from './routes/IndexRoute';
import FlowRoute from './routes/FlowRoute';
import { flowRouteLoader as flowLoader } from '../helpers/RouteLoaders'
const Router = () => {
const router = createBrowserRouter([
{
path: "/",
element: <RootRoute />,
children: [
{
index: true,
element: <IndexRoute />
},
{
path: "flow/:userId",
element: <FlowRoute />,
loader: flowLoader
}
]
},
]);
return (
<RouterProvider router={router} />
)
}
export default Router
Routes
Root Route
import React from 'react'
import { Outlet } from 'react-router-dom';
const RootRoute = () => {
const windowHeight = window.innerHeight;
const divStyle = {
width: '100%',
height: windowHeight*0.9
}
const headerStyle = {
width: '100%',
height: windowHeight*0.1,
backgroundColor: '#000000'
}
return (
<div>
<div style = {headerStyle}>
</div>
<div style = {divStyle}>
<Outlet/>
</div>
</div>
)
}
export default RootRoute
Index Route
import React from 'react'
import { useNavigate } from "react-router-dom";
import Nav from "../../components/Nav.jsx";
const IndexRoute = () => {
const navigate = useNavigate();
const navigationFunction = (email) => {
navigate('/flow/1')
}
return (
<div>
<Nav nav={navigationFunction} />
</div>
)
}
export default IndexRoute
Flow Route
import React from 'react'
import Flow from '../../components/Flow'
import {useLoaderData} from "react-router-dom"
const FlowRoute = () => {
const flow = useLoaderData();
return (
<div>
<Flow nodes = {flow.nodes} edges = {flow.edges}/>
</div>
)
}
export default FlowRoute
Loaders
RouteLoaders.js
export async function flowRouteLoader({params}){
const nodesTemp = [{
id: "1",
type: "input", // input node
data: { label: "Input Node"},
position: { x: 100, y: 0 }
}
]
const edgesTemp = []
const flow = {nodes: nodesTemp, edges: edgesTemp}
return (flow)
}

Fetch to return only one value from mapped urls

I'm in the process of lifting the state up in order to compare ids between the single pokemonCard and the clicked card and make it so that only the clicked card will change from 'captured' to 'not captured'.
At the moment when I try to fetch a single pokemonCard from the mapped urls I currently get all the cards. What I want would basically be setPokemonCard(res[0]) but of course that 0 needs to be dynamic. How can I achieve this?
WARNING: Pokedex and PokemonCard currently still have part of the code I've been lifting up (like the fetch and the url) so that I can see what's happening.
import Header from './components/Header';
import Footer from './components/Footer';
import Pokedex from './pages/Pokedex';
//import PokemonCard from './components/PokemonCard'
import Pokemon from './pages/Pokemon';
import Dropdown from './components/Dropdown';
import { useState, useEffect } from 'react';
import { Routes, Route, BrowserRouter as Router } from 'react-router-dom';
import { PokemonContext } from './context/PokemonContext'
function App() {
const [pokemons, setPokemons] = useState([]);
const [captured, setCaptured] = useState(false)
const URL = 'https://pokeapi.co/api/v2/pokemon/?limit=151';
const [pokemonCard, setPokemonCard] = useState([])
const pokCardURL = pokemons.map(pokemon => pokemon.url)
// console.log(pokCardURL)
//console.log(pokemons)
const fetchingPokemons = async () => {
const res = await fetch(URL);
const data = await res.json();
// console.log(data)
setPokemons(data.results)
}
useEffect(() => {
fetchingPokemons()
}, [URL])
const fetchingPokemonCard = async () => {
//const res = await fetch(pokCardURL);
const res = await Promise.all(pokCardURL.map(url => fetch(url).then((res)=> res.json())));
//const data = await res.json();
setPokemonCard(res[0])
}
useEffect(() => {
fetchingPokemonCard()
}, [pokCardURL])
//console.log(pokemonCard)
const toggleCaptured = () => {
console.log(pokemonCard) //compare pokemonCard.id === card clicked
}
//const toggleCaptured = () => setCaptured(captured => !captured);
const providerValue = {
pokemons,
captured,
toggleCaptured,
}
return (
<PokemonContext.Provider value={providerValue}>
<Router>
<Header />
<Dropdown />
<main className='main'>
<Routes>
<Route exact path="/" element={<Pokedex />} />
<Route path="/pokemon/:id" element={<Pokemon />} />
</Routes>
</main>
<Footer />
</Router>
</PokemonContext.Provider>
)
}
export default App;
import React, { useState, useEffect } from 'react'
import PokemonCard from '../components/PokemonCard';
import { useContext } from 'react';
import { PokemonContext } from '../context/PokemonContext';
const Pokedex = () => {
const {pokemons} = useContext(PokemonContext)
// const [pokemons, setPokemons] = useState([]);
//console.log(captured)
// const URL = 'https://pokeapi.co/api/v2/pokemon/?limit=151';
// const fetchingPokemons = async () => {
// const res = await fetch(URL);
// const data = await res.json();
// // console.log(data)
// setPokemons(data.results)
// }
// useEffect(() => {
// fetchingPokemons()
// }, [URL])
return (
<>
{pokemons.map((pokemon) => {
// console.log(pokemon)
return (
<>
<div style={{ width: '20%' }} key={pokemon.name}>
<PokemonCard
pokemon={pokemon}
name={pokemon.name}
url={pokemon.url}
key={pokemon.name}
/>
</div>
</>
)
})}
</>
)
}
export default Pokedex
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
//import Checkbox from './Checkbox';
import PokemonIcon from './PokemonIcon';
import { useContext } from 'react';
import { PokemonContext } from '../context/PokemonContext';
const PokemonCard = (props) => {
const { url } = props
const { captured, toggleCaptured } = useContext(PokemonContext)
//console.log(pokemonCard)
const URL = url
const [pokemonCard, setPokemonCard] = useState([])
// const [captured, setCaptured] = useState(false)
// const [filteredPokemons, setFilteredPokemons] = useState([])
// const getFilteredPokemon = (id) => {
// if(captured) {
// filteredPokemons.push(pokemonCard)
// //setFilteredPokemons([...filteredPokemons, filteredPokemons])
// console.log(filteredPokemons)
// }
// setFilteredPokemons(pokemonCard.id === id)
// console.log(filteredPokemons)
// }
// const toggleCaptured = () => setCaptured(captured => !captured);
const fetchingPokemonCard = async () => {
const res = await fetch(URL);
const data = await res.json();
//console.log(data)
setPokemonCard(data)
}
useEffect(() => {
fetchingPokemonCard()
}, [URL])
return (
<>
<div className='pokemon-card' style={{
height: '250px',
maxWidth: '250px',
margin: '1rem',
boxShadow: '5px 5px 5px 4px rgba(0, 0, 0, 0.3)',
cursor: 'pointer',
}} >
<Link to={{ pathname: `/pokemon/${pokemonCard.id}` }} state={{ pokemon: pokemonCard, captured }} style={{ textDecoration: 'none', color: '#000000' }}>
<div style={{ padding: '20px', display: 'flex', justifyContent: 'center', alignItems: 'center' }} >
{/* <PokemonIcon img={pokemonCard.sprites?.['front_default']} /> */}
<img style={{
height: '100px',
width: '100px',
}} src={pokemonCard.sprites?.['front_default']} alt='pokemon' />
</div>
</Link>
<div style={{ textAlign: 'center' }}>
<h1 >{pokemonCard.name}</h1>
<label >
<input
type='checkbox'
captured='false'
onChange={toggleCaptured}
/>
<span style={{ marginLeft: 8 }}>
{captured === false ? 'Not captured!' : 'Captured!'}</span>
</label>
</div>
</div>
<div>
</div>
</>
)
}
export default PokemonCard
In your fetchingPokemonCard, just filter the res to match your pokemonCard.id. I don't know what your response looks like so I can't write the filter for you.

How to match an element with data clicked in react hooks?

I am trying to create a modal that will display all the data on the element clicked.
For exemple, if i clicked the id(367) of a movie, it will display the title, the genres and the released date.
First i created a Context.js that will send data in the component Movie.js:
Context.js
import React, { useState, useEffect, createContext } from "react";
import { getAxios } from "../Function/index";
const MovieContext = createContext();
const MovieProvider = ({ children }) => {
const [datas, setDatas] = useState([]);
const [testdatas, testsetDatas] = useState([]);
const getMovie = async () => {
const data = await getAxios(
"https://api.themoviedb.org/3/movie/upcoming?api_key={}"
);
setDatas(data.results);
};
useEffect(() => {
getMovie();
}, []);
return (
<MovieContext.Provider value={{ datas, testdatas }}>{children}</MovieContext.Provider>
);
};
export { MovieContext, MovieProvider };
Movie.js
import React, { useContext } from "react";
import { MovieContext } from '../Context'
import { Card, Row, Tag } from 'antd'
const Main = () => {
const { datas } = useContext(MovieContext)
return (
<Row gutter={16}>
{datas.map((item, id) => (
<Card
key={id}
style={{ width: 300, margin: 10 }} bordered={true}
hoverable
>
<div>
<p style={{ textAlign: "left" }}>{item.title} <span style={{ float: "right" }}>{item.vote_average}</span></p>
</div>
<p><img src={`https://image.tmdb.org/t/p/w500/${item.poster_path}`} alt="#" width="200" height="200" /></p>
<Tag color="red"> {item.title}</Tag>
</Card>
))}
</Row >
);
};
export default Main;

Resources