Я использую axios с реакцией, поэтому я решил написать собственный хук для этого, что я и сделал, и он отлично работает, как показано ниже.
const useAxios = () => {
const [response, setResponse] = useState([]);
const [error, setError] = useState("");
const [loading, setLoading] = useState(true); //different!
const [controller, setController] = useState();
const axiosFetch = async (configObj) => {
const { axiosInstance, method, url, requestConfig = {} } = configObj;
try {
const ctrl = new AbortController();
setController(ctrl);
const res = await axiosInstance[method.toLowerCase()](url, {
...requestConfig,
});
setResponse(res.data);
} catch (err) {
console.info(err.message);
setError(err.message);
} finally {
setLoading(false);
}
};
useEffect(() => {
console.info(controller);
// useEffect cleanup function
return () => controller && controller.abort();
}, [controller]);
return [response, error, loading, axiosFetch];
};
Я также создал один axiosInstance для передачи BASE_URL и заголовков. Теперь вызываем useAxios для получения данных из API, как показано ниже.
const [data, error, loading, axiosFetch] = useAxios();
const getData = () => {
axiosFetch({
axiosInstance: axios,
method: "GET",
url: "/url",
});
};
useEffect(() => {
getData();
}, []);
Мой вопрос
const [data1, error1, loading1, axiosFetch]=useAxios();
Изменить/обновить
Я запустил приведенный выше код, чтобы получить данные из /url, что, если я хочу нажать другой route, чтобы получить еще одни данные с сервера для другой работы, базовый URL-адрес останется прежним.
Итак, если второй маршрут /users
const [data, error, loading, axiosFetch] = useAxios();
const getUsers = () => {
axiosFetch({
axiosInstance: axios,
method: "GET",
url: "/users",
});
};
useEffect(() => {
getUsers();
}, [on_BTN_Click]);
Приведенный выше код я хочу запустить в одном файле, один для получения данных и один для пользователей, как мне написать свои аксиомы, так как я думаю, что это const [data, error, loading, axiosFetch] = useAxios(); должно вызываться только один раз, не знаю, как это сделать или что такое правильно, нужно ли мне менять крючок useAxios?
Что вы можете сделать, так это передать конечную точку хуку или правильно вызвать обратный вызов axiosFetch с разными конечными точками. Но у меня есть другое мнение о том, что вы пытаетесь сделать, и вот мои 5 центов о том, почему этот «хук аксиос» может быть плохой идеей.
Хорошее эмпирическое правило для React Hooks — использовать собственный хук, если вам нужно инкапсулировать логику компонента, использующую React Hooks.
Еще одна важная вещь, которая описана в документации React Hooks:
Пользовательские хуки — это механизм повторного использования логики с отслеживанием состояния (например, настройка подписки и запоминание текущего значения), но каждый раз, когда вы используете пользовательский хук, все состояние и эффекты внутри него полностью изолированы.
Таким образом, в конечном итоге, если 2 разных компонента вызывают выборку для одной и той же конечной точки, они оба будут выполнять вызов к серверной части. Как это предотвратить? Ну, вы могли бы использовать библиотеку, такую как React Query, которая создает для вас своего рода «кеш» (и кучу других приятных функций!)
И последнее, но не менее важное: вызовы API гораздо больше связаны с Service/Module, чем с React Hook (изолировать логику компонента) как концепцию. Я вряд ли советую вам создавать службу для выполнения вызовов API и использования этой службы внутри вашего хука вместо того, чтобы связывать эту логику с вашим хуком и решать всевозможные проблемы, такие как кэширование и несколько экземпляров одного и того же хука или даже несколько экземпляров одного и того же хука. этот хук вызывает несколько разных конечных точек, которые в конечном итоге могут или не могут зависеть сами от себя.
Я не могу использовать ответный запрос по некоторым причинам, не могли бы вы помочь мне с одним примером с этим - I hardly advise you to create a service for making API calls and using that service inside your hook instead of coupling that logic to your hook and having to handle all kinds of issues
Вы можете создать службу запросов (абстракцию) для выполнения ваших запросов (вызовы get, post, patch и delete). Затем, поверх этой службы запросов, вы можете создать другую службу для каждого «домена», которая использует вашу службу запросов «под капотом» и выполнять запросы и предоставлять такие функции, как getProducts() или getProduct(productId), createProduct(productObj). При этом вы изолируете логику и максимально отделяете логику вашего приложения от используемых вами библиотек.
Как насчет общего хука useAsync, который принимает любой асинхронный вызов? Это отделяет специфику аксиом от хука.
function useAsync(func, deps = []) {
const [state, setState] = useState({ loading: true, error: null, data: null })
useEffect(
() => {
let mounted = true
func()
.then(data => mounted && setState({ loading: false, error: null, data }))
.catch(error => mounted && setState({ loading: false, error, data: null }))
return () => { mounted = false }
},
deps,
)
return state
}
Вот основной пример его использования -
function UserProfile({ userId }) {
const user = useAsync(
() => axios.get(`/users/${userId}`), // async call
[userId], // dependencies
})
if (user.loading)
return <Loading />
if (user.error)
return <Error message = {user.error.message} />
return <User user = {user.data} />
}
Идея в том, что можно выполнить любую асинхронную операцию. Более сложный пример может выглядеть так:
function UserProfile({ userId }) {
const profile = useAsync(
async () => {
const user = await axios.get(`/users/${userId}`)
const friends = await axios.get(`/users/${userId}/friends`)
const notifications = await axios.get(`/users/${userId}/notifications`)
return {user, friends, notifications}
},
[userId],
)
if (profile.loading) return <Loading />
if (profile.error) return <Error message = {profile.error.message} />
return <>
<User user = {profile.data.user} />
<Friends friends = {profile.data.friends} />
<Notifications notifications = {profile.data.notifications} />
</>
}
В последнем примере все выборки должны быть завершены, прежде чем данные смогут начать рендеринг. Вы можете использовать хук useAsync несколько раз, чтобы получить параллельную обработку. Не забывайте, что вам нужно проверить loading и error, прежде чем вы сможете безопасно получить доступ к data -
function UserProfile({ userId }) {
const user = useAsync(() => axios.get(`/users/${userId}`), [userId])
const friends = useAsync(() => axios.get(`/users/${userId}/friends`), [userId])
const notifications = useAsync(() => axios.get(`/users/${userId}/notifications`), [userId])
return <>
{ user.loading
? <Loading />
: user.error
? <Error message = {user.error.message }
: <User user = {user.data} />
}
{ friends.loading
? <Loading />
: friends.error
? <Error message = {friends.error.message} />
: <Friends friends = {friends.data} />
}
{ notifications.loading
? <Loading />
: notifications.error
? <Error message = {notifications.error.message} />
: <Notifications notifications = {notifications.data} />
}
</>
}
Я бы порекомендовал вам также отделить аксиомы от ваших компонентов. Вы можете сделать это, написав свой собственный модуль API и даже предоставив крючок useAPI. Посмотрите эти вопросы и ответы, если это покажется вам интересным.
Вам нужно будет написать один хук на запрос. По крайней мере, это образец.