when I use ethers js , I cant connect with contract - javascript

import React, { useEffect, useState } from 'react'
import { abi, contractAddress } from '../config.json'
import { ethers } from "ethers"
import { sync } from 'framer-motion';
//import { toast } from 'react-toastify';
export const BlockchainContext = React.createContext("");
export const BlockchainProvider = ({ children }) => {
const [balance, setBalance] = useState();
const [renterExists, setRenterExists] = useState()
const [renter, setRenter] = useState()
const [currentAccount, setCurrentAccount] = useState("");
let signer = null;
let provider = null;
if (window.ethereum == null) {
console.log("MetaMask not installed; using read-only defaults")
provider = ethers.getDefaultProvider()
} else {
provider = new ethers.BrowserProvider(window.ethereum)
signer = provider.getSigner();
}
const address = contractAddress;
const contractAbi = abi;
const contract = new ethers.Contract(address, contractAbi, signer);
const connectWallet = async () => {
try {
if (!window.ethereum) return alert("please install metamask")
const accounts = await provider.send("eth_requestAccounts");
console.log(accounts[0])
setCurrentAccount(accounts[0])
console.log(currentAccount)
} catch (error) {
console.log(error)
throw new Error("no ethereum object")
}
}
const checkifWalletIsConnected = async () => {
try {
if (!window.ethereum) return alert("Please install Metmask")
const accounts = await provider.send("eth_accounts");
if (accounts.length) {
setCurrentAccount(accounts[0])
} else {
console.log("No accounts found")
}
} catch (error) {
console.log(error)
}
}
const checkRenterExists = async () => {
try {
if (currentAccount) {
const renter = await contract.renterExists(currentAccount)
setRenterExists(renter);
if (renter) {
await getRenter();
}
}
} catch (error) {
console.log(error)
}
}
const getRenter = async () => {
try {
if (currentAccount) {
const renter = await contract.getRenter(currentAccount)
setRenter(renter)
}
} catch (error) {
console.log(error)
}
}
useEffect(() => {
checkifWalletIsConnected()
connectWallet
}, [currentAccount])
return (
<BlockchainContext.Provider
value={{ connectWallet, currentAccount, renterExists }}
>
{children}
</BlockchainContext.Provider>
)
}
enter image description here
I think the problem here
enter image description here
I cant use
const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer = provider.getSigner()
const address = contractAddress;
const contractAbi = abi;
const contract = new ethers.Contract(address, contractAbi, signer);
enter image description here
Everything else works
But I think the problem is
const contract = new ethers. Contract(address, contractAbi, signer);
Also, it seems that the ethers library does not contain ethers.providers

you are using ethers.js v6
This is the signature for getDefaultProvider
function getDefaultProvider(network: string | Networkish | WebSocketLike, options?: any): AbstractProvider
import getDefaultProvider
you need to pass network url as string
second thing provider.getSigner() returns Promise.
BrowserProvider.getSigner(address?: string | number | undefined): Promise<ethers.JsonRpcSigner>
you should add then() or write the logic inside async function so that you can await it

Related

How to inject a service in a api conext?

I have a api context and I have a service. And I try to write the logic in each of the components.
So I have the service:
const CategoryService = () => {
const fetchCategoryData = async () => {
try {
const response = await fetch("http://192.168.1.68:19000/animal/categories/main_groups/", {
method: "GET",
});
if (!response.ok) {
throw new Error("Network response was not ok");
}
return await response.json();
} catch (error) {
console.error("There was a problem with the fetch operation:", error);
throw error;
}
};
return fetchCategoryData;
};
export default CategoryService;
and I have the context:
import { createContext, useState } from "react";
const CategoryContext = createContext();
const CategoryContextProvier = (props) => {
const [categoryList, setCategoryList] = useState([]);
const [loading, setLoading] = useState(false);
const value = {
categoryList,
loading,
setCategoryList,
setLoading,
};
return <CategoryContext.Provider value={value}>{props.children}</CategoryContext.Provider>;
};
export default CategoryContextProvier;
Question: how to communicate these two witch each other?
you can just call fetchCategoryData in CategoryContextProvier useEffect
like this
const CategoryContextProvier = (props) => {
const [categoryList, setCategoryList] = useState([]);
const [loading, setLoading] = useState(false);
const value = {
categoryList,
loading,
setCategoryList,
setLoading,
};
useEffect(()=>{
setLoading(true);
fetchCategoryData()
.then(res=> setCategoryList(res))
.finally(()=> setLoading(false));
},[])
return <CategoryContext.Provider value={value}>{props.children}</CategoryContext.Provider>;
};

WalletConnect Error : Uncaught (in promise) TypeError: o.getSubtleCrypto() is undefined ( while running it in test server )

I've been trying to implement wallet-connect login in test server (with http:// ) where as it works perfectly in production server ( https:// ).
It gives me this error while running Wallet Conneect in test server :
https://i.stack.imgur.com/6kMXx.png
Unable to identify a solution for it , can anyone help me with it ?
here's my code so far :
import React, { useState, useContext, useMemo, useCallback } from "react";
import Web3Modal from "web3modal";
import { Web3Provider } from "#ethersproject/providers";
import WalletConnectProvider from "#walletconnect/web3-provider";
import { URI } from "../constant";
import Web3 from "web3";
import { getSymbol } from "./helpers/get-symbol";
import { switchNetwork } from "./helpers/swtich-networks";
import config from "../actions/config"
const Web3Context = React.createContext();
export const useWeb3Context = () => {
const web3Context = useContext(Web3Context);
if (!web3Context) {
throw new Error("useWeb3Context() can only be used inside of <Web3ContextProvider />, " + "please declare it at a higher level.");
}
const { onChainProvider } = web3Context;
return useMemo(() => {
return { ...onChainProvider };
}, [web3Context]);
};
export const useAddress = () => {
const { address } = useWeb3Context();
return address;
};
export const Web3ContextProvider = ({ children }) => {
const [connected, setConnected] = useState(false);
const [chainID, setChainID] = useState(1);
const [providerChainID, setProviderChainID] = useState();
const [address, setAddress] = useState("");
const [symbol, setSymbol] = useState("");
const [balance, setBalance] = useState("0");
const [networkName, setNetworkName] = useState("");
const [provider, setProvider] = useState(URI.ETH);
const web3Modal =
new Web3Modal({
cacheProvider: true,
bridge: "https://bridge.walletconnect.org",
providerOptions: {
walletconnect: {
package: WalletConnectProvider,
options: {
rpc:
1: "https://mainnet.infura.io/v3/",
4: "https://rinkeby.infura.io/v3/",
137: "https://polygon-rpc.com/",
80001: "https://matic-mumbai.chainstacklabs.com",
}
},
},
},
});
const hasCachedProvider = () => {
if (!web3Modal) return false;
if (!web3Modal.cachedProvider) return false;
return true;
};
const _initListeners = useCallback(
(rawProvider) => {
if (!rawProvider.on) {
return;
}
rawProvider.on("accountsChanged", () => setTimeout(() => window.location.reload(), 1));
rawProvider.on("chainChanged", async (chain) => {
changeNetwork(chain);
window.location.reload()
});
rawProvider.on("network", (_newNetwork, oldNetwork) => {
if (!oldNetwork) return;
window.location.reload();
});
},
[provider],
);
const changeNetwork = async (otherChainID) => {
connect()
const network = Number(otherChainID);
console.log(network)
setProviderChainID(network);
};
const connect = useCallback(async () => {
try {
const rawProvider = await web3Modal.connect();
_initListeners(rawProvider);
const connectedProvider = new Web3Provider(rawProvider, "any");
const chainId = await connectedProvider.getNetwork().then(network => Number(network.chainId));
const connectedAddress = await connectedProvider.getSigner().getAddress();
const networkName = await connectedProvider.getNetwork().then(network => String(network.name))
//Production part code below.
if (config.env == "prod") {
if (chainId == 80001 || chainId == 4) {
disconnect()
alert("Wrong Network Detected , Please Switch to Mainnet for Polygon or Ethereum.")
//await switchNetwork(chainId)
return
}
}
if (chainId !== null) {
const web3 = new Web3(Web3.givenProvider);
// console.log(Web3.givenProvider)
const userBalance = await web3.eth.getBalance(connectedAddress) / Math.pow(10, 18);
setBalance(userBalance);
}
setAddress(connectedAddress);
setProviderChainID(chainId);
setSymbol(getSymbol(chainId));
setChainID(chainId);
setNetworkName(networkName);
setProvider(connectedProvider);
setConnected(true);
localStorage.setItem("address", connectedAddress);
localStorage.setItem("walletconnect", true);
localStorage.setItem("networkVersion", chainId);
return connectedProvider;
} catch (error) {
console.log(error);
}
}, [provider, web3Modal, connected]);
const checkWrongNetwork = () => {
if (providerChainID == 1 || providerChainID == 137) {
return false;
}
return true;
};
const disconnect = useCallback(async () => {
web3Modal.clearCachedProvider();
setConnected(false);
window.location.href = "/";
localStorage.removeItem("walletconnect")
localStorage.removeItem("networkVersion")
localStorage.removeItem("address")
localStorage.removeItem("pkscontract")
localStorage.removeItem("pksbal")
}, [provider, web3Modal, connected]);
const onChainProvider = useMemo(
() => ({
connect,
disconnect,
switchNetwork,
hasCachedProvider,
provider,
connected,
address,
symbol,
balance,
networkName,
chainID,
web3Modal,
providerChainID,
checkWrongNetwork,
}),
[connect, disconnect, hasCachedProvider, provider, connected, address, symbol, networkName, balance, chainID, web3Modal, providerChainID],
);
//#ts-ignore
return <Web3Context.Provider value={{ onChainProvider }}>{children}</Web3Context.Provider>;
};
export default Web3ContextProvider;
It's tricky to make some wallet work in local host, wallet connect is one of them. One work around is to use a service like ngrok, which will give a https link for your localhost and it will work fine.

Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component. - useEffect()

I get this error when I try and call a function I have imported within my useEffect() hook in Dashboard.jsx. I am just trying to pull in data from database on the page load pretty much so that when user click button they can send off correct credentials to the api.
I am pulling it in from database for security reasons, so client id is not baked into the code.
I am pretty sure that I am getting this error maybe because the function is not inside a react component? although I am not 100% sure. And if that is the case I am not sure of the best way to restructure my code and get the desired output.
Code below.
mavenlinkCredentials.js
import { doc, getDoc } from "firebase/firestore";
import { useContext } from "react";
import { AppContext } from "../../context/context";
import { db } from "../../firebase";
const GetMavenlinkClientId = async () => {
const {setMavenlinkClientId} = useContext(AppContext)
const mavenlinkRef = doc(db, 'mavenlink', 'application_id');
const mavenlinkDocSnap = await getDoc(mavenlinkRef)
if(mavenlinkDocSnap.exists()){
console.log("mavenlink id: ", mavenlinkDocSnap.data());
console.log(mavenlinkDocSnap.data()['mavenlinkAccessToken'])
setMavenlinkClientId(mavenlinkDocSnap.data()['application_id'])
} else {
console.log("No doc");
}
}
export default GetMavenlinkClientId;
Dashboard.jsx
import React, { useContext, useEffect, useState } from "react";
import { useAuthState } from "react-firebase-hooks/auth";
import { useNavigate } from "react-router-dom";
import { query, collection, getDocs, where, setDoc, doc, getDoc } from "firebase/firestore";
import { auth, db, logout } from "../firebase";
import { Button, Container, Grid, Paper } from "#mui/material";
import ListDividers from "../components/ListDividers";
import { AppContext } from "../context/context";
import axios from "axios";
import {SuccessSnackbar, ErrorSnackbar} from '../components/PopupSnackbar';
import GetMavenlinkClientId from "../helpers/firebase/mavenlinkCredentials";
const Dashboard = () => {
const [user, loading, error] = useAuthState(auth);
const [name, setName] = useState("");
const [ accessToken, setAccessToken ] = useState("")
const [errorAlert, setErrorAlert] = useState(false);
const [successAlert, setSuccessAlert] = useState(false);
const [mavenlinkClientId, setMavenlinkClientId] = useState("");
const {isAuthenticated} = useContext(AppContext);
const navigate = useNavigate();
const uid = user.uid
const parsedUrl = new URL(window.location.href)
const userTokenCode = parsedUrl.searchParams.get("code");
const { mavenlinkConnected, setMavenlinkConnected } = useContext(AppContext)
const { maconomyConnected, setMaconomyConnected } = useContext(AppContext)
const { bambooConnected, setBambooConnected } = useContext(AppContext)
const fetchUserName = async () => {
try {
const q = query(collection(db, "users"), where("uid", "==", user?.uid));
const doc = await getDocs(q);
const data = doc.docs[0].data();
setName(data.name);
} catch (err) {
console.error(err);
alert("An error occured while fetching user data");
}
};
//
useEffect(() => {
if (loading) return;
if (!user) return navigate("/");
fetchUserName();
if(userTokenCode !== null){
authorizeMavenlink();
}
if(isAuthenticated){
GetMavenlinkClientId()
}
}, [user, loading]);
///put this into a page load (use effect maybe) so user does not need to press button to connect to apis
const authorizeMavenlink = () => {
console.log(uid);
const userRef = doc(db, 'users', uid);
axios({
//swap out localhost and store in variable like apitool
method: 'post',
url: 'http://localhost:5000/oauth/mavenlink?code='+userTokenCode,
data: {}
})
.then((response) => {
setAccessToken(response.data);
setDoc(userRef, { mavenlinkAccessToken: response.data}, { merge: true });
setMavenlinkConnected(true);
setSuccessAlert(true);
})
.catch((error) => {
console.log(error);
setErrorAlert(true)
});
}
//abstract out client id and pull in from db
const getMavenlinkAuthorization = () => {
window.open('https://app.mavenlink.com/oauth/authorize?client_id='+mavenlinkClientId+'&response_type=code&redirect_uri=http://localhost:3000');
window.close();
}
const authorizeBamboo = () => {
axios({
method: 'get',
url: 'http://localhost:5000/oauth/bamboo',
data: {}
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error);
});
// console.log('bamboo connected')
setBambooConnected(true);
}
const authorizeMaconomy = () => {
console.log("Maconomy connected")
setMaconomyConnected(true);
}
const syncAccount = async() => {
if(!mavenlinkConnected){
await getMavenlinkAuthorization()
}
if (!bambooConnected){
await authorizeBamboo();
}
if (!maconomyConnected){
await authorizeMaconomy();
}
}
const handleAlertClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
setSuccessAlert(false) && setErrorAlert(false);
};
console.log(mavenlinkClientId);
return(
<>
<Container>
<div className="dashboard">
<h1>Dashboard</h1>
<Grid container spacing={2}>
<Grid item xs={12}>
<Paper style={{paddingLeft: "120px", paddingRight: "120px"}} elevation={1}>
<div className="dashboard-welcome">
<h2>Welcome {name}</h2>
<h4>{user?.email}</h4>
<hr/>
<h2>Integrations</h2>
<Button onClick={syncAccount}>
Sync Account
</Button>
{/* <Button onClick={getMavenlinkClientId}>
Bamboo Test
</Button> */}
<ListDividers/>
</div>
</Paper>
</Grid>
</Grid>
</div>
{successAlert === true ? <SuccessSnackbar open={successAlert} handleClose={handleAlertClose}/> : <></> }
{errorAlert === true ? <ErrorSnackbar open={errorAlert} handleClose={handleAlertClose}/> : <></> }
</Container>
</>
);
}
export default Dashboard;
the error is because you’re calling const {setMavenlinkClientId} = useContext(AppContext) inside the file mavenlinkCredentials.js which is not a react components.
you could maybe change the function inside mavenlinkCredentials.js to accept a setMavenlinkClientId and pass it from outside like this.
const GetMavenlinkClientId = async (setMavenlinkClientId) => {
const mavenlinkRef = doc(db, 'mavenlink', 'application_id');
const mavenlinkDocSnap = await getDoc(mavenlinkRef)
if(mavenlinkDocSnap.exists()){
console.log("mavenlink id: ", mavenlinkDocSnap.data());
console.log(mavenlinkDocSnap.data()['mavenlinkAccessToken'])
setMavenlinkClientId(mavenlinkDocSnap.data()['application_id'])
} else {
console.log("No doc");
}
}
and then you can call this function in your dashboard.js like so,
const {setMavenlinkClientId} = useContext(AppContext)
if(isAuthenticated){
GetMavenlinkClientId(setMavenlinkClientId)
}

while trying to return firebase data to another page it passes undefined

I'm trying to fetch data from Firebase, I implemented nearly same codes like my react native app but this time I'm facing some problems that I couldn't figure out.
import {db} from './firebase'
const formatMarketData = (data) =>{
let formattedData = [];
data.forEach(item=>{
const formattedItem = {
...item
}
formattedData.push(formattedItem);
});
return formattedData;
}
export const FirebaseService = async (id) => {
id=id.replace(/['"]+/g, "");
const historyKey="/coins/0/"+id
await
db.ref(historyKey)
.once('value')
.then(snapshot => {
const data = snapshot.val();
const formattedResponse= formatMarketData(data);
console.log(formattedResponse)
return formattedResponse
});
};
This function helps me to retrieve data from my firebase rtdb. The console.log functions works and writes as expected but when I'm trying to catch it in my News page it becomes undefined.
import React from 'react'
import { useState,useEffect } from 'react'
import { FirebaseService } from '../../Services/FirebaseService'
const NewList = ({id}) => {
const [data,setData] = useState([])
useEffect(()=>{
console.log(id)
const fetchMarketData = async () =>{
const marketData = await FirebaseService(id);
return setData(marketData);
}
fetchMarketData();
return () => {
}
},[])
return (
<div>
{data!==undefined?data.map((d)=>{return(<p>{d.id}</p>)})
:<p>no data yet</p>}
</div>
)
}
export default NewList
I'm missing something but I can't notice. Another view might be helpful.
Define formattedResponse at start of function and return it at very end.
I have edited you function
import {db} from './firebase'
const formatMarketData = (data) =>{
let formattedData = [];
data.forEach(item=>{
const formattedItem = {
...item
}
formattedData.push(formattedItem);
});
return formattedData;
}
export const FirebaseService = (id) =>{
let formattedResponse = [];
id=id.replace(/['"]+/g, "");
const historyKey="/coins/0/"+id
await
db.ref(historyKey)
.once('value')
.then(snapshot => {
const data = snapshot.val();
formattedResponse=
formatMarketData(data);
console.log(formattedResponse)
})
return formattedResponse
};

Refreshing UI after deleting item in React

I'm new to React and I have the issue that my UI ain't refreshing once I send a delete fetch in my React app. I tried to use a useEffect on my deleteTaskHandler but it broke my code. Any ideas how to accomplish this refresh?
This is my Task.js file, which is receiving props from a TaskList.js file, and TaskList.js file sends a component to App.js:
import React, { useState } from 'react';
import classes from './Task.module.css';
const Task = (props) => {
const [isCompleted, setIsCompleted] = useState(props.isCompleted);
const changeCompleteStatus = () => {
setIsCompleted(!isCompleted);
}
const deleteTaskHandler = async () => {
try {
const key = props.id
const response = await fetch('http://localhost:5050/delete-task/' + key, {
method: 'DELETE'
});
if (!response.ok) {
throw new Error('Something went wrong!');
};
const data = await response.json();
console.log(data);
} catch (error) {
console.log(error);
}
};
const updateTaskHandler = async () => {
const id = props.id
const taskData = {
id: id,
content: props.content,
isCompleted: !props.isCompleted,
dateCreation: props.dateCreation,
};
try {
const response = await fetch('http://localhost:5050/edit-task/' + id, {
method: 'PATCH',
body: JSON.stringify(taskData),
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Something went wrong!');
};
const data = await response.json();
console.log(data);
} catch (error) {
console.log(error);
}
};
let task;
if (props.isAllView) {
task = <div >
<input type="checkbox" onClick={updateTaskHandler} onChange={changeCompleteStatus} checked={isCompleted} />
<h2>{props.content}</h2>
<h3>{props.dateCreation}</h3>
<button onClick={deleteTaskHandler}>X</button>
</div>
} else {
task = <div >
<h2>{props.content}</h2>
<h3>{props.dateCreation}</h3>
</div>
}
return (
<li>{task}</li>
);
};
export default Task;
This is TaskList.js:
import React, { useState } from 'react';
import classes from './TaskList.module.css';
import Task from './Task';
const TaskList = (props) => {
const [taskView, setTaskView] = useState('all');
const getCompleteURL = () => {
setTaskView('complete')
props.onChangeTaskURL('http://localhost:5050/completed');
};
const getAllURL = () => {
setTaskView('all')
props.onChangeTaskURL('http://localhost:5050/');
};
const getPendingURL = () => {
setTaskView('pending')
props.onChangeTaskURL('http://localhost:5050/pending');
};
let taskList;
if (taskView != 'all') {
taskList = props.taskData.map((task) => (
<Task
key={task.id}
content={task.content}
dateCreation={task.dateCreation}
isCompleted={task.isCompleted}
isAllView={false}
/>
));
} else {
taskList = props.taskData.map((task) => (
<Task
key={task.id}
id={task.id}
content={task.content}
dateCreation={task.dateCreation}
isCompleted={task.isCompleted}
isAllView={true}
/>
));
}
return (
<div>
<ul >
{taskList}
</ul>
<button onClick={getCompleteURL}>Completed</button>
<button onClick={getAllURL}>All</button>
<button onClick={getPendingURL}>Pending</button>
</div>
);
};
export default TaskList;
This is App.js:
import React, { useState, useEffect, useCallback } from 'react';
import './App.css';
import TaskList from './components/Tasks/TaskList';
import NewTask from './components/NewTask/NewTask';
function App() {
const [tasks, setTasks] = useState([]);
const [taskURL, setTaskURL] = useState('http://localhost:5050/');
const fetchTasksHandler = useCallback(async (url) => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Something went wrong!');
}
const data = await response.json();
const loadedTasks = [];
for (const key in data) {
loadedTasks.push({
id: data[key]._id,
content: data[key].content,
isCompleted: data[key].isCompleted,
dateCreation: data[key].dateCreation
});
}
console.log(loadedTasks)
setTasks(loadedTasks);
} catch (error) {
// throw new Error('Something went wrong!');
console.log(error)
}
}, []);
useEffect(() => {
fetchTasksHandler(taskURL);
}, [fetchTasksHandler, taskURL]);
const changeTaskURL = url => {
console.log(url)
setTaskURL(url);
};
return (
<React.Fragment>
<TaskList taskData={tasks} onChangeTaskURL={changeTaskURL}></TaskList>
<NewTask></NewTask>
</React.Fragment>
);
}
export default App;
Extract deleteTaskHandler and updateTaskHandler in your App.js and pass them down to the TaskList => Task. In both methods, on successful operation update the tasks state array (for delete - filter out the deleted task, for update - swap the old task with the updated one). This way, the Task component will call the relevant handler which will update the parent tasks state, which in turn will spill down to the TaskList and Task and everything will get updated automatically.
Here is a sample. Consider it more as a pseudo code as you'll have to modify some of the parts to handle your case appropriately.
Your Task.js:
import React, { useState } from 'react';
import classes from './Task.module.css';
const Task = (props) => {
const {
updateTaskHandler,
deleteTaskHandler
} = props;
const [isCompleted, setIsCompleted] = useState(props.isCompleted);
const changeCompleteStatus = () => {
setIsCompleted(!isCompleted);
}
const updateHandler = () => {
const taskData = {
id: id,
content: props.content,
isCompleted: !props.isCompleted,
dateCreation: props.dateCreation,
};
updateTaskHandler(props.id, taskData);
};
const deleteHandler = () => {
deleteTaskHandler(props.id);
};
let task;
if (props.isAllView) {
task = <div >
<input type="checkbox" onClick={updateHandler} onChange={changeCompleteStatus} checked={isCompleted} />
<h2>{props.content}</h2>
<h3>{props.dateCreation}</h3>
<button onClick={deleteHandler}>X</button>
</div>
} else {
task = <div >
<h2>{props.content}</h2>
<h3>{props.dateCreation}</h3>
</div>
}
return (
<li>{task}</li>
);
};
export default Task;
TaskList.js:
import React, { useState } from 'react';
import classes from './TaskList.module.css';
import Task from './Task';
const TaskList = (props) => {
const [taskView, setTaskView] = useState('all');
const getCompleteURL = () => {
setTaskView('complete')
props.onChangeTaskURL('http://localhost:5050/completed');
};
const getAllURL = () => {
setTaskView('all')
props.onChangeTaskURL('http://localhost:5050/');
};
const getPendingURL = () => {
setTaskView('pending')
props.onChangeTaskURL('http://localhost:5050/pending');
};
let taskList;
if (taskView != 'all') {
taskList = props.taskData.map((task) => (
<Task
key={task.id}
content={task.content}
dateCreation={task.dateCreation}
isCompleted={task.isCompleted}
isAllView={false}
updateTaskHandler={props.updateTaskHandler}
deleteTaskHandler={props.deleteTaskHandler}
/>
));
} else {
taskList = props.taskData.map((task) => (
<Task
key={task.id}
id={task.id}
content={task.content}
dateCreation={task.dateCreation}
isCompleted={task.isCompleted}
isAllView={true}
updateTaskHandler={props.updateTaskHandler}
deleteTaskHandler={props.deleteTaskHandler}
/>
));
}
return (
<div>
<ul >
{taskList}
</ul>
<button onClick={getCompleteURL}>Completed</button>
<button onClick={getAllURL}>All</button>
<button onClick={getPendingURL}>Pending</button>
</div>
);
};
export default TaskList;
And App.js:
import React, { useState, useEffect, useCallback } from 'react';
import './App.css';
import TaskList from './components/Tasks/TaskList';
import NewTask from './components/NewTask/NewTask';
function App() {
const [tasks, setTasks] = useState([]);
const [taskURL, setTaskURL] = useState('http://localhost:5050/');
const fetchTasksHandler = useCallback(async (url) => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Something went wrong!');
}
const data = await response.json();
const loadedTasks = [];
for (const key in data) {
loadedTasks.push({
id: data[key]._id,
content: data[key].content,
isCompleted: data[key].isCompleted,
dateCreation: data[key].dateCreation
});
}
setTasks(loadedTasks);
}
catch (error) {
// throw new Error('Something went wrong!');
console.log(error)
}
}, []);
const deleteTaskHandler = async (taskID) => {
try {
const response = await fetch(`http://localhost:5050/delete-task/${taskID}`, {
method: 'DELETE'
});
if (!response.ok) {
throw new Error('Something went wrong!');
};
const data = await response.json();
setTasks(tasks => {
return tasks.filter(task => task.id !== taskID)
});
}
catch (error) {
console.log(error);
}
};
const updateTaskHandler = async (taskID, taskData) => {
const id = props.id
const taskData = {
id: id,
content: props.content,
isCompleted: !props.isCompleted,
dateCreation: props.dateCreation,
};
try {
const response = await fetch(`http://localhost:5050/edit-task/${taskID}`, {
method: 'PATCH',
body: JSON.stringify(taskData),
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Something went wrong!');
};
const data = await response.json();
setTasks(tasks => {
return tasks.map(task => {
if (task.id !== taskID) {
return task;
}
else {
return data; // The updated task
}
})
});
}
catch (error) {
console.log(error);
}
};
useEffect(() => {
fetchTasksHandler(taskURL);
}, [fetchTasksHandler, taskURL]);
const changeTaskURL = url => {
console.log(url)
setTaskURL(url);
};
return (
<React.Fragment>
<TaskList
taskData={tasks}
onChangeTaskURL={changeTaskURL}
deleteTaskHandler={deleteTaskHandler}
updateTaskHandler={updateTaskHandler}
/>
<NewTask />
</React.Fragment>
);
}
export default App;
You have to pass a callback that removes a task and pass it as a prop to the Task component.
In your App.js:
function deleteTask(id) {
setTasks(loadedTasks.filter(x => x.id !== id);
}
// ...
<TaskList taskData={tasks} onDelete={deleteTask}></TaskList>
In your TaskList.js:
tasks.map(task => <Task id={task.id} key={task.id} onDelete={props.deleteTask}></Task>)
In the Task.js call props.deleteTask(props.id) whenever you need to.
Note that passing a prop through two components or more is called "prop drilling" and should be avoided (by keeping the state in TaskList.js for example).
you can use
window.location.reload();
to refresh the page or
this.setState({});
to refresh the component or
const [value,setValue] = useState();
const refresh = ()=>{
setValue({});
}
to refresh the component using hooks
i hope you found this answer helpful

Categories

Resources