[英]How to trigger a hook once a state has changed in a functional component?
I'm writing a custom pagination hook that'll fetch an API and will return some data to me like React Query.我正在编写一个自定义分页钩子,它将获取一个 API 并将一些数据返回给我,比如 React Query。 Fairly simple.相当简单。 What I'm trying to do is to trigger that hook when a state(in this case cursor
) updates.我想要做的是在状态(在这种情况下cursor
)更新时触发该钩子。
Here's the hook itself:这是钩子本身:
import axios from "../api/axios";
import { useEffect, useRef, useState } from "react";
interface FetchInfiniteResourceProps {
// The URL of the API endpoint
url: string;
// Cursor of the page
cursor: number;
// Parameter with which the backend accepts the cursor number
queryParam: string;
// The property on the response which will indicate if the next page exists
nextPageParam: string;
// Other config
config: {
enabled: boolean;
};
}
// Prop types for useFetchInfiniteResource
interface StateProps {
data: any[];
isLoading: boolean;
hasNextPage: boolean;
isFetchingNextPage: boolean;
}
/**
* This function will be used for fetching
* an infinite resource from the back-end
*/
export const useFetchInfiniteResource = ({
url,
cursor,
queryParam,
nextPageParam,
config: { enabled },
}: FetchInfiniteResourceProps) => {
// Creating a new state
const [state, setState] = useState<Partial<StateProps>>({
data: [],
isLoading: true,
hasNextPage: false,
isFetchingNextPage: false,
});
// Method for setting the data
const setData = (newState: []) => setState({ data: newState });
// The function for sending the request
const request = async () => {
// If it's not the first time that this request has triggered
if (!state.isLoading) setState({ ...state, isFetchingNextPage: true });
// Sending the request
const { data: response } = await axios.get(url, {
params: {
// Query paramter
[queryParam]: cursor,
},
});
// Updating the state
setState({
// If it's the first time that this request is invoked
isLoading: state?.isLoading && false,
// Merging the data
data: state?.data?.concat(response.data),
// Checking if the next page exists
hasNextPage: response[nextPageParam] !== null,
// If it's not the first time that the request is invoked then set it to false
isFetchingNextPage: !state?.isLoading && false,
});
};
const requestRef = useRef(async () => await request());
useEffect(() => {
if (enabled) requestRef.current();
}, [enabled]);
// Returning all the items from the state and the function to update the data manually
return { ...state, setData };
};
And here's the component:这是组件:
const SomeComponent = () => {
const [cursor, setCursor] = useState(0);
const {...} = useFetchInfiniteResource({ cursor, ... }); // Problem here
someListener(() => {
setCursor(cursor + 1); // Problem here
});
return ...
}
I think I'm misusing the useEffect or the useRef hook, but so far I have tried also using the useCallback hook.我想我误用了 useEffect 或 useRef 钩子,但到目前为止我也尝试过使用 useCallback 钩子。
Thanks for your help谢谢你的帮助
Try wrapping the request function in a useEffect
hook with just the cursor in the dependency array.尝试将 request 函数包装在useEffect
钩子中,并且只使用依赖项数组中的游标。 ESLint won't like it, but it should work. ESLint 不会喜欢它,但它应该可以工作。
Stripped down example:精简示例:
const useFetchInfiniteResource = ({
cursor,
...
}: FetchInfiniteResourceProps) => {
const [state, setState] = useState<Partial<StateProps>>({ ... });
const setData = (newState: []) => setState({ data: newState });
useEffect(() => {
const request = async () => {
if (!state.isLoading) setState({ ...state, isFetchingNextPage: true });
const { data: response } = await axios.get(url, {
params: {
[queryParam]: cursor,
},
});
setState({ ... });
};
if (enabled) request();
}, [cursor]);
return { ... };
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.