Use Effect causing infinite re-renders

Hey everyone, I'm a little confused on how to fix this, I'm fetching a list of engineers which I want to be able to use in a select dropdown, but when trying to map over, and set to state, its causing an infinite re-render, here is my code
function CreateTimesheetScreen({
navigation,
}: RootStackScreenProps<"CreateTimesheet">) {
const { getToken, signOut } = useAuth();
const { user } = useUser();
const [formLoading, setFormLoading] = React.useState(false);
const [engineersValue, setEngineersValue] = React.useState(null);
const [open, setOpen] = React.useState(false);
const [items, setItems] = React.useState<EngineerItem[]>([]);

const [sessionToken, setSessionToken] = React.useState("");
const [date, setDate] = React.useState(new Date());

React.useEffect(() => {
const scheduler = setInterval(async () => {
const token = await getToken();
setSessionToken(token as string);
}, 1000);

return () => clearInterval(scheduler);
}, []);

const today = new Date();

const {
control,
handleSubmit,
formState: { errors },
setValue,
setError,
} = useForm({
defaultValues: {
work_provider: "",
date_of_work: today,
order_num: "",
work_item: "",
quantity: "",
notes: "",
gang_price_split: "",
},
});

type Data = {
work_provider: string;
date_of_work: string;
order_num: string;
work_item: number;
quantity: string;
notes: string;
gang_price_split: string;
};
function CreateTimesheetScreen({
navigation,
}: RootStackScreenProps<"CreateTimesheet">) {
const { getToken, signOut } = useAuth();
const { user } = useUser();
const [formLoading, setFormLoading] = React.useState(false);
const [engineersValue, setEngineersValue] = React.useState(null);
const [open, setOpen] = React.useState(false);
const [items, setItems] = React.useState<EngineerItem[]>([]);

const [sessionToken, setSessionToken] = React.useState("");
const [date, setDate] = React.useState(new Date());

React.useEffect(() => {
const scheduler = setInterval(async () => {
const token = await getToken();
setSessionToken(token as string);
}, 1000);

return () => clearInterval(scheduler);
}, []);

const today = new Date();

const {
control,
handleSubmit,
formState: { errors },
setValue,
setError,
} = useForm({
defaultValues: {
work_provider: "",
date_of_work: today,
order_num: "",
work_item: "",
quantity: "",
notes: "",
gang_price_split: "",
},
});

type Data = {
work_provider: string;
date_of_work: string;
order_num: string;
work_item: number;
quantity: string;
notes: string;
gang_price_split: string;
};
2 Replies
max14
max1410mo ago
const onSubmit = async (data: Data) => {
setFormLoading(true);
const gangPriceSplit = data.gang_price_split.split("/");
const gangPriceSplitSum = +gangPriceSplit[0] + +gangPriceSplit[1];
if (gangPriceSplitSum !== 100) {
setError("gang_price_split", {
type: "manual",
message: "Gang price split should add up to 100",
});
}

if (!errors.root) {
const {
work_provider,
order_num,
work_item,
quantity,
notes,
gang_price_split,
} = data;

const quantityNum = +quantity;
const workItem = work_item.toString();
const ISODate = date.toISOString();

const form = {
work_provider,
order_num,
work_item: workItem,
quantity: quantityNum,
notes,
gang_price_split,
date_of_work: ISODate,
};

await axios.post(`https://api.fibreflo.com/timesheets`, form);
setFormLoading(false);
}
};

const addSlash = (value: any) => {
if (value.length === 3) {
value += "/";
}
setValue("gang_price_split", value);
};

const onDateChange = (event: any, selectedDate: any) => {
const currentDate = selectedDate;
setDate(currentDate);
};

const { isLoading, error, data, refetch } = useQuery<Engineer[], Error>(
["engineers"],
fetchEngineers
);

useRefreshOnFocus(refetch);

if (isLoading) return <LoadingIndicator />;

if (error)
return (
<View>
<Text>Error</Text>
</View>
);

const engineers = data;

if (!engineers) return null;

const transformedItems = React.useMemo(() => {
return engineers.map((engineer: Engineer) => {
return {
label: `${engineer.first_name} ${engineer.last_name}`,
value: engineer.id,
};
});
}, [engineers]);

React.useEffect(() => {
setItems(transformedItems);
}, [transformedItems]);
const onSubmit = async (data: Data) => {
setFormLoading(true);
const gangPriceSplit = data.gang_price_split.split("/");
const gangPriceSplitSum = +gangPriceSplit[0] + +gangPriceSplit[1];
if (gangPriceSplitSum !== 100) {
setError("gang_price_split", {
type: "manual",
message: "Gang price split should add up to 100",
});
}

if (!errors.root) {
const {
work_provider,
order_num,
work_item,
quantity,
notes,
gang_price_split,
} = data;

const quantityNum = +quantity;
const workItem = work_item.toString();
const ISODate = date.toISOString();

const form = {
work_provider,
order_num,
work_item: workItem,
quantity: quantityNum,
notes,
gang_price_split,
date_of_work: ISODate,
};

await axios.post(`https://api.fibreflo.com/timesheets`, form);
setFormLoading(false);
}
};

const addSlash = (value: any) => {
if (value.length === 3) {
value += "/";
}
setValue("gang_price_split", value);
};

const onDateChange = (event: any, selectedDate: any) => {
const currentDate = selectedDate;
setDate(currentDate);
};

const { isLoading, error, data, refetch } = useQuery<Engineer[], Error>(
["engineers"],
fetchEngineers
);

useRefreshOnFocus(refetch);

if (isLoading) return <LoadingIndicator />;

if (error)
return (
<View>
<Text>Error</Text>
</View>
);

const engineers = data;

if (!engineers) return null;

const transformedItems = React.useMemo(() => {
return engineers.map((engineer: Engineer) => {
return {
label: `${engineer.first_name} ${engineer.last_name}`,
value: engineer.id,
};
});
}, [engineers]);

React.useEffect(() => {
setItems(transformedItems);
}, [transformedItems]);
Ramsay
Ramsay10mo ago
remove the items state and just use transformedItems