I have a component and I want to fetch isbn data on button click using react hook useEffect, performing a get
on the route ${basicUrl}/editorials/${isbn}
, so i wrote this component:
import React, { Fragment, useState } from "react";
import "./Home.css";
import { V3_BASIC_URL } from "../../constants/endpoints";
import { useDataApi } from "../../store/effects/dataEffects";
import SearchIsbnElement from "../../components/SearchIsbnElement/SearchIsbnElement";
import IsbnPanelElement from "../../components/IsbnPanelElement/IsbnPanelElement";
function Home() {
const [query, setQuery] = useState<string>("9788808677853");
const [isValid, setIsValid] = useState<boolean>(true);
const url = `${V3_BASIC_URL(
process.env.REACT_APP_API_ENV
)}/editorials/${query}`;
const [{ isbn, isLoading, isError }, doFetch] = useDataApi(url, {
isLoading: false,
isError: false,
isbn: undefined,
});
const buttonCallback = () => {
doFetch(url);
};
const isbnRegexp = /^97\d{11}$/
const validateQuery = (query: string): boolean => isbnRegexp.test(query)
const inputCallback = (query: string) => {
setQuery(query)
setIsValid(validateQuery(query));
};
return (
<div id="isbn-panel-home" className="Home">
<SearchIsbnElement
inputCallback={inputCallback}
buttonCallback={buttonCallback}
query={query}
isValid={isValid}
></SearchIsbnElement>
{isError && <div>Il servizio al momento non è disponibile, riprova più tardi</div>}
{isLoading ? (
<div>Loading ...</div>
) : (
!isError &&
<Fragment>
<IsbnPanelElement isbn={isbn}></IsbnPanelElement>
<p>{isbn?.scheda_volume == null && 'isbn non trovato'}</p>
</Fragment>
)}
</div>
);
}
export default Home;
the useDataApi
function uses the hook useEffect and returns state
and setUrl
action to set the new url on isbn value change. This is the useDataApi
file:
import { useState, useEffect, useReducer } from "react";
import {
dataFetchFailure,
dataFetchInit,
dataFetchSuccess,
} from "../actions/dataActions";
import { dataFetchReducer, ISBNState } from "../reducers/dataReducers";
import { get } from "../../tools/request";
type InitialState = {
isLoading: boolean,
isError: boolean,
isbn: undefined,
}
export const useDataApi = (initialUrl: string, initialData: InitialState) : [ISBNState, (value: string) => void] => {
const [url, setUrl] = useState(initialUrl);
const [state, dispatch] = useReducer(dataFetchReducer, initialData);
useEffect(() => {
let didCancel: boolean = false;
const fetchData = async (): Promise<any> => {
dispatch(dataFetchInit());
const options = {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
auth: {
username: `${process.env.REACT_APP_API_AUTH_USER}`,
password: `${process.env.REACT_APP_API_AUTH_PWD}`
}
}
try {
const {data} = await get(url, options);
if (!didCancel) {
dispatch(dataFetchSuccess(data));
}
} catch (error) {
if (!didCancel) {
dispatch(dataFetchFailure(error));
}
}
};
fetchData();
return () => {
didCancel = true;
};
}, [url]);
return [state, setUrl];
};
with this code fetching starts on page load, but i want to fetch data only on button click. How can I do this?
useEffect() is a hook to manipulate the component through the different lifecycle methods. In order to do something onClick you need to create a method for that:
const fetchData = async (): Promise<any> => {
dispatch(dataFetchInit());
const options = {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
auth: {
username: `${process.env.REACT_APP_API_AUTH_USER}`,
password: `${process.env.REACT_APP_API_AUTH_PWD}`
}
}
try {
const {data} = await get(url, options);
if (!didCancel) {
dispatch(dataFetchSuccess(data));
}
} catch (error) {
if (!didCancel) {
dispatch(dataFetchFailure(error));
}
}
};
Just do that and you will be fine
Edit: the new version of useDataApi
export const useDataApi = (
url: string,
initialData: InitialState
): [ISBNState, (value: string) => void] => {
const [state, dispatch] = useReducer(dataFetchReducer, initialData);
const fetchData = useCallback(async (): Promise<any> => {
dispatch(dataFetchInit());
const options = {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
auth: {
username: `${process.env.REACT_APP_API_AUTH_USER}`,
password: `${process.env.REACT_APP_API_AUTH_PWD}`,
},
};
try {
const { data } = await get(url, options);
dispatch(dataFetchSuccess(data));
} catch (error) {
dispatch(dataFetchFailure(error));
}
}, [url]);
return [state, fetchData];
};