I have a ponent called Invoice.js. This has more than 1000 lines of code. I do want to break a few methods and their relevant useState stuff to a separate file.
I have an array called items
and API call to fill the array.
const [items, setItems] = useState([]);
// load items
const loadItems = async () => {
try {
let items = await axios.get("/item");
setItems(items.data);
} catch (error) {
setAlert({
showAlert: true,
severity: "error",
message: "Customer loading failed!",
});
}
};
Please note that I am calling this array in the useEffect
hook.
// use effect hook
useEffect(() => {
//load active agents
loadAgent();
//load items
loadItems();
}, []);
I do want to break this whole thing into a separate file and just import the items
array.
Another case is addItem
method.
const addItem = (e) => {
// check this item already added
const foundItem = initialValues.items.find((itm) => itm.id === item.id);
if (foundItem) {
setAlert({
showAlert: true,
severity: "error",
message: "This item already added!",
});
} else {
const originalItem = items.find((el) => el.id === item.id);
const { id, description, size } = originalItem;
const newEl = {
id,
description,
size,
unitPrice: Number(item.unitPrice).toFixed(2),
qty: item.qty,
amount: (Number(item.qty) * Number(item.unitPrice)).toFixed(2),
};
setInitialValues({
...initialValues,
items: [...initialValues.items, newEl],
});
}
};
In this case, this function depends on both items array and initialValues
object.
How do I achieve this using React, with keeping mind if something went wrong inside these functions I need to fire the setAlert
method in the Invocie.js ponent.
I have a ponent called Invoice.js. This has more than 1000 lines of code. I do want to break a few methods and their relevant useState stuff to a separate file.
I have an array called items
and API call to fill the array.
const [items, setItems] = useState([]);
// load items
const loadItems = async () => {
try {
let items = await axios.get("/item");
setItems(items.data);
} catch (error) {
setAlert({
showAlert: true,
severity: "error",
message: "Customer loading failed!",
});
}
};
Please note that I am calling this array in the useEffect
hook.
// use effect hook
useEffect(() => {
//load active agents
loadAgent();
//load items
loadItems();
}, []);
I do want to break this whole thing into a separate file and just import the items
array.
Another case is addItem
method.
const addItem = (e) => {
// check this item already added
const foundItem = initialValues.items.find((itm) => itm.id === item.id);
if (foundItem) {
setAlert({
showAlert: true,
severity: "error",
message: "This item already added!",
});
} else {
const originalItem = items.find((el) => el.id === item.id);
const { id, description, size } = originalItem;
const newEl = {
id,
description,
size,
unitPrice: Number(item.unitPrice).toFixed(2),
qty: item.qty,
amount: (Number(item.qty) * Number(item.unitPrice)).toFixed(2),
};
setInitialValues({
...initialValues,
items: [...initialValues.items, newEl],
});
}
};
In this case, this function depends on both items array and initialValues
object.
How do I achieve this using React, with keeping mind if something went wrong inside these functions I need to fire the setAlert
method in the Invocie.js ponent.
- Remember that hooks can only be used within ponents. You could probably split the Invoice ponent into smaller ponents where every ponent will be responsible for something else, i.e. list of items, total values, customer info etc. – szczocik Commented Oct 12, 2020 at 9:08
3 Answers
Reset to default 4You could write a custom hook, pass in all dependencies as parameters and return all the functions and states:
function useItems({ setAlert }) {
const [items, setItems] = useState([]);
async function loadItems() { ... }
function addItem(item) { ... }
useEffect(() => { loadItems(); }, []);
return { items, addItem };
}
// Then embed as
function setAlert() { ... }
const { items, addItem } = useItems({ setAlert });
The hook is then independent from the ponent, and can be moved into another file.
Basically what you need is custom hook.Something like this
const useItems = setAlert => {
const [items, setItems] = useState([]);
// load items
const loadItems = async () => {
try {
const items = await axios.get("/item");
setItems(items.data);
} catch (error) {
setAlert({
showAlert : true,
severity : "error",
message : "Customer loading failed!",
});
}
};
return [items, loadItems];
};
And you call it on anywhere like this. As it was before
const [itemd, loadItems] = useItems(setAlert);
useEffect(() => {
loadItems()
}, []);
I would say custom Hooks are the solutions you are looking for, to be exact on your use case -
You might want to create a custom hook useItems and transfer the code of useState and useEffect to that file and just write
const {data, error} = useItems();
Your useItems could be like
export default () => {
const [items, setItems] = useState([]);
const [error, setError] = useState(null)
useEffect(() => {
//your fetch code
}, [])
return {data: items, error}
}
To make this generic what I did it, I create custom hooks for different types of network calls.
like usePost, useGet etc handling the different data trigger cases I had.