General Advice with apollo hooks and too many re renders - reactjs

background: I am trying to achieve a file upload with DropZone to s3 and graphql serving presigned url for puts and gets and while it might not be perfect it does work. The issue I am having now is when I add in useMutation to push the result to graphlql end which write to mongodb database I am getting too many re renders so looking for advice on how to really understand whats going on here. As ugly as my code may be the upload to s3 works once I don’t have addFileS3(file) the addFileS3(file) is call useMutation to grpahql to write the result to mongoDB so I can retrieve the file at later point so i assumed the best
place for it was the response from axios.
const DropZone = ({ folderId, folderProps }) => {
const [createS3File] = useMutation(ADD_FILE_S3);
const addFileS3 = (file) => {
createS3File({
variables: {
folderId: folderId,
fileName: file.name,
},
})
.then(({ data }) => {
console.log("data", data);
})
.catch((e) => {
console.log(e);
});
};
const {
acceptedFiles,
getRootProps,
getInputProps,
isDragActive,
isDragAccept,
isDragReject,
} = useDropzone({ accept: "image/*, application/pdf" });
const [
getPutURL,
{ loading: loading_url, error: error_url, data: data_url },
] = useLazyQuery(GET_S3_PUT_URL);
if (loading_url) {
console.log("loading");
} else if (error_url) {
console.log(error_url);
} else if (data_url) {
const results = data_url.PUTURL;
results.map((file) => {
const fileResult = acceptedFiles.filter(function(fileAcc) {
return fileAcc.name === file.name;
});
const options = {
params: {
Key: file.name,
ContentType: file.type,
},
headers: {
"Content-Type": file.type,
},
};
axios
.put(file.url, fileResult[0], options)
.then((res) => {
//once i add the below here or outside axios post it goes mental on uploads
addFileS3(file);
})
.catch((err) => {
});
});
}
const acceptedFilesItems = acceptedFiles.map((file) => {
return (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
);
});
const uploadDocs = () => {
let files = [];
acceptedFiles.map((file) => {
const fileObj = { name: file.name, type: file.type };
files.push(fileObj);
});
return getS3URLResult(files);
};
const getS3URLResult = async (files) => {
getPutURL({
variables: {
packet: files,
},
});
};
return (
<StyledDropZone>
<div className="container">
<Container
{...getRootProps({ isDragActive, isDragAccept, isDragReject })}
>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</Container>
{acceptedFilesItems}
</div>
<button onClick={() => uploadDocs(acceptedFiles)}>Upload</button>
</StyledDropZone>
);
};

You're making axios request during render 'flow', not in event handler/chain. It's called, changes state and causes next rerendering - infinite loop.
Both mutation and lazy query have possibility to use onCompleted handler. This is a place to chain/invoke next action (using data result parameter).
... alse hanlder should not return anything (return getS3URLResult(files);) - just call it (getS3URLResult(files);) or directly getPutURL.
update
Probably you're looking for something like this:
const DropZone = ({ folderId, folderProps }) => {
const {
acceptedFiles,
getRootProps,
getInputProps,
isDragActive,
isDragAccept,
isDragReject,
} = useDropzone({ accept: "image/*, application/pdf" });
const uploadDocs = () => {
let files = [];
acceptedFiles.map((file) => {
const fileObj = { name: file.name, type: file.type };
files.push(fileObj);
});
console.log("uploadDocs, from acceptedFiles", files);
// return getS3URLResult(files);
getPutURL({
variables: {
packet: files,
},
});
};
const [
getPutURL,
{ loading: loading_url, error: error_url, data: data_url },
] = useLazyQuery(GET_S3_PUT_URL, {
onCompleted: (data) => {
console.log("PUT_URL", data);
const results = data.PUTURL;
results.map((file) => {
const fileResult = acceptedFiles.filter(function(fileAcc) {
return fileAcc.name === file.name;
});
const options = {
params: {
Key: file.name,
ContentType: file.type,
},
headers: {
"Content-Type": file.type,
},
};
axios
.put(file.url, fileResult[0], options)
.then((res) => {
console.log("axios PUT", file.url);
// addFileS3(file);
createS3File({
variables: {
folderId: folderId,
fileName: file.name,
},
})
})
.catch((err) => {
});
});
}
});
const [createS3File] = useMutation(ADD_FILE_S3,{
onCompleted: (data) => {
console.log("ADD_FILE_S3", data);
//setUploadedFiles( uploadedFiles,concat(data.somefilename) );
}
});
const [uploadedFiles, setUploadedFiles] = useState( [] );
const acceptedFilesItems = acceptedFiles.map((file) => {
return (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
);
});
const renderUploadedFiles ...
return (
<StyledDropZone>
<div className="container">
<Container
{...getRootProps({ isDragActive, isDragAccept, isDragReject })}
>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</Container>
{acceptedFilesItems}
{uploadedFiles.length && <div class="success">
{renderUploadedFiles}
</div>}
</div>
<button onClick={() => uploadDocs(acceptedFiles)}>Upload</button>
</StyledDropZone>
);
};
Some optimalizations should be added (useCallback), not placed for clarity.
For more readability and optimization (limit rerenderings) ... I would move almost all (processing) into separate subcomponent - pass acceptedFiles as prop, render upload button inside.

Related

React-paypal advanced integration errors

I have been trying to implement React-Paypal advanced integration for almost a week now but I keep getting an error. I did not use api from paypal sandbox, instead I'm calling our own api built with dotnet.
When I proceed with payment, order Id was created but the payment declined.
Working flow that I want to achieve is;
onClick Prepare for payment will generate all data that I need to process in the back end. Then, on render or onClick Pay, it will create an order including orderId and capture the payment.
Can anyone spot where I went wrong on my code below?
Error:
Checkout.jsx
import { useState } from "react"
import {
PayPalScriptProvider
} from "#paypal/react-paypal-js";
import CheckoutButton from "./CheckoutButton";
import "../styles/Checkout.css";
import NewCheckoutBtn from "./Checkout2";
const PrepareForPayment = () => {
const [clientId, setClientId] = useState(null)
const [clientToken, setClientToken] = useState(null)
const [merchantRef, setMerchantRef] = useState(null)
const [sessionHash, setSessionHash] = useState(null)
const [showData, setShowData] = useState(false);
const baseUrl = "http://local.payment.web"
const onClick = async () => {
console.log("onClick ran");
return await fetch(`${baseUrl}/api/Ppal/ReactApi/PrepareForPayment`, {
mode: "cors",
method: "post",
headers: {
'content-type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
"curCode": "USD",
"orderAmount": 500
})
}).then(res => {
console.log("fetch Data : ", res);
return res.json()
}).then(data => {
console.log("fetch Data : ", data);
setShowData(true)
setClientId(data.ClientId)
setClientToken(data.ClientToken)
if (data.prepareForPayment) {
setMerchantRef(data.merchantRef)
setSessionHash(data.sessionHash)
}
}).catch(err => console.log(err))
}
return (
<>
<button onClick={onClick} disabled={showData ? true : false}>Prepare for payment</button>
{
clientToken && (
<PayPalScriptProvider
options={{
"client-id": clientId,
components: "buttons,hosted-fields",
"data-client-token": clientToken,
intent: "capture",
vault: false,
}}
>
<CheckoutButton merchantRef={merchantRef} sessionHash={sessionHash} />
</PayPalScriptProvider>
)
}
</>
)
}
export default PrepareForPayment
CheckoutButton.jsx
import { useState, useRef, useEffect } from "react";
import { usePayPalHostedFields, usePayPalScriptReducer } from "#paypal/react-paypal-js";
import "../styles/CheckoutBtn.css";
import { useCallback } from "react";
const CheckoutButton = ({ merchantRef, sessionHash }) => {
const [paid, hasPaid] = useState(false)
const [orderId, setOrderId] = useState(null)
const [supportsHostedFields, setSupportsHostedFields] = useState(null)
const [renderInstance, setRenderInstance] = useState()
const cardHolderName = useRef(null);
const hostedField = usePayPalHostedFields();
const [{ isResolved, options }] = usePayPalScriptReducer()
const paypal = window.paypal
const baseUrl = "http://local.payment.web"
const initPaypal = useCallback(async () => {
if (typeof supportsHostedFields === "boolean" && !!supportsHostedFields) {
const instance = await paypal.HostedFields.render({
createOrder: function() {
return fetch(`${baseUrl}/api/Ppal/ReactApi/CreateOrder2`, {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
merchantRef: merchantRef,
sessionHash: sessionHash,
orderId: orderId,
intent: "capture",
})
}).then(res => {
console.log("res from createOrder", res);
return res.json()
}).then(data => {
console.log("orderId from initialize : ", data?.orderId);
if (data?.createOrder) return setOrderId(data?.orderId)
}).catch(err => console.log(err))
},
styles: {
input: {
"font-size": "16pt",
color: "#3A3A3A"
},
".number": {
"font-family": "monospace"
},
".valid": {
color: "green"
}
},
fields: {
number: {
selector: "#card-number",
placeholder: "Credit Card Number"
},
cvv: {
selector: "#cvv",
placeholder: "CVV"
},
expirationDate: {
selector: "#expiration-date",
placeholder: "MM/YYYY"
}
}
})
setRenderInstance(instance)
}
}, [merchantRef, sessionHash, orderId, paypal, supportsHostedFields])
useEffect(() => {
if (isResolved) {
setSupportsHostedFields(paypal.HostedFields.isEligible());
}
}, [setSupportsHostedFields, options, isResolved, paypal]);
useEffect(() => {
initPaypal()
}, [initPaypal])
const handleClick = (e) => {
e.preventDefault()
console.log("Order id onclick : ", orderId);
renderInstance.submit().then((data) => {
console.log("Reach here?");
const captureOrder = async () => {
return await fetch(`${baseUrl}/api/Ppal/ReactApi/CaptureOrder`, {
mode: "cors",
method: "post",
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
merchantRef: merchantRef,
sessionHash: sessionHash
})
}).then((res) => {
console.log("res from pay button : ", res);
return res.json()
}).then((data) => {
console.log("data from pay button : ", data);
if(data.isApproved) {
alert("Payment successful")
hasPaid(true)
}
if(!data.isApproved) alert("Payment declined")
if(data.isExpired) alert("Payment expired")
})
}
captureOrder().catch((err) => {
console.log(err)
})
return data
})
console.log("Card holder : ", cardHolderName.current.value);
console.log("merchant ref : ", merchantRef);
console.log("Order id onclick after : ", orderId);
};
return (
<form onSubmit={handleClick}>
<label htmlFor="card-number">Card Number</label>
<div id="card-number"></div>
<label htmlFor="expiration-date">Expiration Date</label>
<div id="expiration-date"></div>
<label htmlFor="cvv">CVV</label>
<div id="cvv"></div>
<button value="submit" id="submit" className="btn">
Pay with Card
</button>
</form>
)
};
export default CheckoutButton;
As others have pointed out, the error in your screenshot comes from this line inside of handleClick
console.log("Card holder : ", cardHolderName.current.value);
You've initialized cardHolderName with null.
const cardHolderName = useRef(null);
But then your code appears to do nothing with that ref. So that current value of the ref will always be null.
To fix the error, remove the reverence to cardHolderName.current.value, or set the value of the ref to an object with a value property.

How to remove all file uploaded with upload component of ant design

Is there a way to delete all uploaded files at once? When I uploaded success. I want to call event remove all files. I didn't find any solution for this. Tks for all the help !
Here is my code:
upload file
const [fileDatas, setFileDatas] = useState([]);
const dummyRequest = ({ file, onSuccess }) => {};
const beforeUpload = (file, fileList) => {return false};
const { Dragger } = Upload;
const props = {
accept: 'image/png, image/jpeg, image/svg, image/gif, .xlsx,.xls,image/*,.doc, .docx,.ppt, .pptx,.txt,.pdf',
name: 'file',
multiple: true,
beforeUpload: beforeUpload,
action: dummyRequest,
onChange({ file, fileList }) {
if (file.status !== 'uploading') {
setFileUploads(fileList);
}
},
onDrop(e) {
console.log('Dropped files', e.dataTransfer.files);
setFileUploads(e.dataTransfer.files);
},
};
handle event submit upload file
const handleUploadFile = () => {
if (fileUploads.length === 0) {
toastActionWarning('No files to upload');
}else{
setFileUploads([]);
const formDatas = new FormData();
fileUploads.forEach((file) => {
formDatas.append(file.name, file.originFileObj);
});
axios
.post('files', formDatas, { withCredentials: true })
.then((res) => {
let newList = [...fileDatas];
res.data.data.forEach(element => {
element.author = window.userDisplayName;
newList = [element, ...newList]
});
setFileDatas(newList);
//I want to clear all file here
toastActionSuccess('Upload successfully');
})
.catch((error) => {
toastActionFailed('There was an error in processing');
});
}
};

How to fetch api via looped callbacks with React functional components

So I have a 40+ loop that's calling another component to display images. Each image has an ID and with that ID I can get more information about the image like Name and description via another API call.
When DisplayImage gets called I want it to call another callback function that will send out API calls for that image's metadata, store it in a variable and display it as an H1 tag.
return (
<div>
{array.map(index) => {
// Some Other Code That return a TokenID //
<>
{displayImage(tokenId)}
</>
</div>
})
const displayImage = (tokenId) => {
const imageName = GetURI(tokenId)
return (
<div className="token-container">
<h1>{imageName}</h1>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
}
const GetURI = async (tokenId) => {
const res = await fetch("https://api"+tokenId , {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
}).then(data => {
console.log(data)
return data.json();
})
.then(data => {
return (data.name || [])
})
.catch(err => {
console.log(err);
});
}
The data is being displayed on the console but now I'm running into an infinite loop issue that I know UseEffect can solve but I can't quite figure it out. I managed to display the data on the console with UseEffect using the [] attribute but don't know how to display the data. Any help would be amazing. Thank you!
Two things useful to your situation
functions declared outside the component aren't recreated each render
useState and useEffect pairing limits calls to API to only when tokenId changes
// Put this function outside the component
// so it does not need a useCallback
// i.e not reconstructed each render of DisplayImage
const GetURI = async (tokenId) => {
...
});
const DisplayImage = (tokenId) => {
const [imageName, setImageName] = useState()
// limit calls to API to when tokenId changes
// and if eslint complains add GetURI to dependency list
// - but GetURI never changes, so no un-needed calls from it
useEffect(() => {
setImageName(GetURI(tokenId))
}, [tokenId, GetURI])
return (
<div className="token-container">
<h2>{imageName}</h2>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
};
You can also abstract to custom hook useImageName()
const GetURI = async (tokenId) => {
...
});
const useImageName = (tokenId) => {
const [imageName, setImageName] = useState()
useEffect(() => {
setImageName(GetURI(tokenId))
}, [tokenId, GetURI])
return imageName
})
const DisplayImage = (tokenId) => {
const imageName = useImageName(tokenId)
return (
<div className="token-container">
<h2>{imageName}</h2>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
};
BTW in GetURI this
return (data.name || [])
looks like should be
return data.name || ''
Is a different approach ok? I'd put display image into its own component.
const DisplayImage = ({tokenId: {_tokenId}}) => {
const imageName = GetURI(_tokenId)
const GetURI = useCallback(async () => {
await fetch("https://api"+tokenId , {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
}).then(data => {
console.log(data)
return data.json();
})
.then(data => {
return (data.name || [])
})
.catch(err => {
console.log(err);
});
})
});
useEffect(() => {
if (_tokenId) GetURI();
}, [GetURI]);
return (
<div className="token-container">
<h2>{imageName}</h2>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${_tokenId}`} />
</div>
)
};
and then
return (
<div>
{array.map(index) => {
//Some Other Code//
<DisplayImage tokenId={tokenId} />
</div>
})
You should probably cache the response from GetURI(tokenId). No need to ask twice for the same URI when using the same tokenId.
An easy way is using react-query:
Setup in App.js:
// App.js
import { QueryClient, QueryClientProvider } from 'react-query'
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
Then use in a DisplayImage component (instead of inline function):
// DisplayImage.js
import { useQuery } from 'react-query'
export function DisplayImage(tokenId) {
const { isLoading, error, data: imageName } = useQuery(['images', tokenId], GetURI(tokenId))
return (
<div className="token-container">
<h1>{isLoading ? 'loading...' : imageName}</h1>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
}
I found the best way to go about it with everyones help on here so thanks!
I put the GetURI function inside the show image component, and had a useEffect method call GetURI every time there was a new token ID, then I set a state variable to whatever was returned.
No loops, no errors 👌
const DisplayImage = (data) => {
const [nftMetadata, setNftMetadata] = useState();
const GetURI = async (data) => {
const nftURI = await data.drizzle.contracts.Contract.methods.tokenURI(data.tokenId).call()
await fetch(nftURI , {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
"Access-Control-Allow-Origin": "*"
},
})
.then(data => {
return data.json();
})
.then(data => {
return setNftMetadata(data || []);
})
.catch(err => {
return console.log(err);
});
});
useEffect(() => {
GetURI(data);
}, [data.tokenId])
return (
<div className="token-container">
<h2>{nftMetadata.name}</h2>
<img className="artwork" width="450px" src={`https://ipfs:/whatever/${nftMetadata.image}`} />
</div>
);
};
return (
<div>
{array.map(index) => {
// Some Other Code That returns a TokenID //
<>
<DisplayImage address={drizzle.contractList[0].address} tokenId={tokenId} drizzle={drizzle} drizzleState={drizzleState}/>
</>
</div>
})

React project- chatting app. Need advice on setting interval

below is my main code for my project, which is a simple open chatting room.
This is a chatting client basically, which can only get chatting logs and post chats.
To log in, I request for an authorization key to the server and use that key to start chatting.
The thing that I want to do is to get the chatting logs from the server every 3 seconds.
So, after it retrieves chats every 3 seconds, the page should refresh with new chats.
However, this seems not to be working well for me.
If there is a good React pro who can solve this problem for me, please do.
import React from 'react';
import { withRouter } from 'react-router-dom';
import './Chat.css';
import InfoBar from '../InfoBar/InfoBar';
import Input from '../Input/Input';
import Messages from '../Messages/Messages';
const API_ENDPOINT = 'https://snu-web-random-chat.herokuapp.com';
let INTERVAL_ID;
const Chat = ({ token, setToken }) => {
const [ name, setName ] = React.useState('');
const [ message, setMessage ] = React.useState('');
const [ messages, setMessages ] = React.useState([]);
const [ lastEl, setLastEl ] = React.useState({});
React.useEffect(() => {
if (localStorage.getItem('username')) {
setName(localStorage.getItem('username'));
}
window.addEventListener('scroll', listenToScroll, true);
fetchData();
INTERVAL_ID = setInterval(() => {
fetchData();
}, 3000);
return () => {
window.removeEventListener('scroll', listenToScroll);
clearInterval(INTERVAL_ID);
};
}, []);
const fetchData = () => {
fetch(`${API_ENDPOINT}/chats?createdAtFrom=${lastEl.createdAt || ''}`)
.then((res) => res.json())
.then((msgs) => {
const updatedMsgs = messages.concat(msgs);
setLastEl(msgs[msgs.length - 1]);
setMessages(updatedMsgs);
});
};
const listenToScroll = (e) => {
const div = document.getElementById('messagesContainer');
// console.log(window.scrollY);
// const winScroll = document.body.scrollTop || document.documentElement.scrollTop;
// const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
// const scrolled = winScroll / height;
};
const onLogin = (e) => {
e.preventDefault();
fetch(`${API_ENDPOINT}/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `name=${name}`
})
.then((response) => response.json())
.then(({ key }) => {
if (key) {
setToken(true);
localStorage.setItem('__key', key);
localStorage.setItem('username', name);
}
})
.catch((err) => console.error(err));
};
const sendMessage = (e) => {
e.preventDefault();
if (message) {
fetch(`${API_ENDPOINT}/chats`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Key ${localStorage.getItem('__key')}`
},
body: `message=${message}`
})
.then((response) => response.json())
.then((res) => {
const obj = {
createdAt: res.createdAt,
message: res.message,
userName: res.user.name,
_id: res.user._id
};
setMessages([ ...messages, obj ]);
})
.catch((err) => console.error(err));
setMessage('');
}
};
const logout = () => {
localStorage.removeItem('__key');
localStorage.removeItem('username');
setToken(false);
};
const loadMessages = () => {
fetchData();
clearInterval(INTERVAL_ID);
};
return (
<div className="outerContainer">
<div className="innerContainer">
<InfoBar
name={name}
token={token}
handleInput={(e) => setName(e.target.value)}
handleLogin={onLogin}
handleLogout={logout}
/>
<Messages messages={messages} name={name} lastEl={lastEl} loadMore={loadMessages} />
{token && <Input message={message} setMessage={setMessage} sendMessage={sendMessage} />}
</div>
</div>
);
};
export default withRouter(Chat);
I can give u the advice to make a chat app with socket.io, not setInterval.
https://socket.io/get-started/chat

Failed to Fetch using Knex JS in in React App

I have a component with a checkbox that I'm keeping track of through a localhost db using postgres. When i check the checkboxes, a row is inserted into the table netowrkusers with the login user id in the id column, and the id of the user that was checked in the connections column. It removes the row when unchecked. It seems to work intermittently-but I keep getting a 'failed to fetch' error, and eventually the database doesn't keep proper track of the checked and unchecked boxes. Could someone that knows Knex see if there is a flaw in the code? Here is the Knex.js code I'm using.
app.post("/cb", (req, res) => {
const { loginuser, userid, ischecked } = req.body;
if (ischecked) {
console.log("flag is true");
db.transaction(trx => {
trx
.insert({
id: loginuser,
connections: userid
})
.into("networkusers")
.returning("id", "connections")
.then(() => {
console.log("committing");
trx.commit();
})
.catch(error => {
console.log("error", error);
trx.rollback();
});
}).catch(err => res.status(400).json(err));
} else {
console.log("flag is false");
db.transaction(trx => {
db("networkusers")
.where("id", "=", loginuser)
.andWhere("connections", "=", userid)
.del()
.returning("id", "connections")
.then(() => {
console.log("committing");
console.log(loginuser,userid)
trx.commit();
})
.catch(error => {
console.log("error", error);
trx.rollback();
});
}).catch(err => res.status(400).json(err));
}
});
And here is the components that have the checkbox logic:
import React, { useState } from "react";
const onUpdateCB = (ischecked, loginuser, userid, setisChecked,handleCheck) => {
console.log(ischecked, loginuser, userid);
fetch('http://localhost:3000/cb', {
method: 'post',
headers: {'Content-Type':'application/json'},
body:JSON.stringify({
loginuser,
userid,
ischecked: ischecked
})
}).then(setisChecked(ischecked));
return
};
const Card = props => {
const [isChecked, setisChecked] = useState(props.ischecked);
return (
<div
className="pointer bg-light-green dib br3 pa3 ma2 shadow-5"
onClick={() => props.handleClick(props.id)}
>
<div>
<h3>{props.name}</h3>
<p>{props.company}</p>
<p>{props.phone}</p>
<p>{props.email}</p>
<p>{props.city}</p>
</div>
<div>
My Network
<input
className="largeCheckbox"
type="checkbox"
checked={isChecked}
onChange={() =>
onUpdateCB(!isChecked, props.loginuser.id, props.id, setisChecked,props.handleCheck)
}
/>
</div>
</div>
);
};
export default Card;
NetworkArray component:
import React from "react";
import Card from "./Card";
const NetworkArray = ({
network,
networkusers,
handleChange,
handleClick,
loginuser
}) => {
console.log("in network array", networkusers);
const cardComponent = network.map((user, i) => {
const ischecked = networkusers.filter(n => {
var nw = n.id === loginuser.id && n.connections === network[i].id;
return nw;
});
console.log("is it checked", ischecked);
return (
<Card
key={network[i].id}
name={network[i].firstname + " " + network[i].lastname}
company={network[i].company}
phone={network[i].phone}
email={network[i].email}
city={network[i].city}
ischecked={ischecked.length}
handleChange={handleChange}
handleClick={handleClick}
id={network[i].id}
loginuser={loginuser}
/>
);
});
return <div>{cardComponent}</div>;
};
export default NetworkArray;
This doesn't look quite right:
db.transaction(trx => {
db("networkusers")
.where("id", "=", loginuser)
Normally you'd do:
db.transaction(trx => {
trx("networkusers")
.where("id", "=", loginuser)
or:
db.transaction(trx => {
db("networkusers")
.where("id", "=", loginuser)
.transacting(trx)
I suspect the issue is you're just not using the transaction object consistently. See overview.
You should also respond after your database operation succeeds (not just when it fails). So something like:
db
.transaction(trx => {
// ...query...
})
.then(() => res.json({ message: 'Success.' }))
.catch(err => res.status(400).json(err));

Resources