Reputation: 171
Hi I'm new to Node/React, and I'm creating a learning project. It's platform that connects freelancers with nonprofit companies. Users (freelancers), view a list of companies, and click a button to connect to a company. Once this is clicked, the user will have that company added as a relationship in the database. This is working correctly.
Now I'd like users to visit a page and view their "connections", basically all the companies they connected with. In the database, I'm only storing the "companyHandle" in the association table. So currentUser.connections
would give me an array of companyHandles ['aapl', 'gogl', 'msft']
. So when the user views their connections, I would like to fetch data from the backend API, to retrieve more information about each company (companyName, numEmployees, etc..).
I tried to do that by looping through all the companyHandles, and fetching data from the API for each company, but I get the error React Hook "useEffect" may be executed more than once. Possibly because it is called in a loop..
.
What's a better way to do this? How can I fetch data for different companies? Below is my code (shortened)
schema
CREATE TABLE companies (
company_handle VARCHAR(25) PRIMARY KEY,
password TEXT NOT NULL,
company_name TEXT NOT NULL,
country TEXT NOT NULL,
num_employees INTEGER CHECK (num_employees > 0)
);
CREATE TABLE users (
username VARCHAR(25) PRIMARY KEY,
password TEXT NOT NULL,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT NOT NULL CHECK (position('@' IN email) > 1)
);
CREATE TABLE connections (
username VARCHAR(25)
REFERENCES users ON DELETE CASCADE,
company_handle VARCHAR(25)
REFERENCES companies ON DELETE CASCADE,
PRIMARY KEY (username, company_handle)
);
UserConnections.js
function UserConnections() {
const { currentUser } = useContext(UserContext);
const connections = currentUser.connections;
const [companies, setCompany] = useState([]);
if (connections) {
for (const connection in connections) {
useEffect(function getCompanyDetail() {
async function getCompany() {
setCompany(await VolunteerApi.getCurrentCompany(connection));
}
getCompany();
}, [connection]);
}
}
return (
<div>
{companies.length
? (
<div>
{companies.map(company => (
<CompanyCard
key={company.companyHandle}
companyHandle={company.companyHandle}
companyName={company.companyName}
country={company.country}
numEmployees={company.numEmployees}
/>
)
)}
</div>
) : (
<p>You have no connections</p>
)}
</div>
);
};
Upvotes: 1
Views: 449
Reputation: 21
You can use promise.all
to execute promises (api fetcher) and useEffect
hook from React.
useEffect(() => {
setLoading(true); // If you want to add loader or spinner till companies info fetched
const connectionsPromises = connections.map((connection) => {
return VolunteerApi.getCurrentCompany(connection);
});
Promise.all(connectionsPromises).then((companies) => {
setCompany(companies); // save companies
setLoading(false); // disable loader
});
}, [connections])
Promise.all resolves promises parallelly
Upvotes: 2
Reputation: 688
Basically, you can only use hooks at the top level of your component.
Take a look at the rules of hooks (including useEffect).
You should try to put your if
and for
loop inside the useEffect
.
Upvotes: 0