我正在使用Robin Wieruch的出色著作来了解如何调用API端点。这是他的项目之一:https://github.com/the-road-to-learn-react/react-hooks-introduction
下面显示的是他的useDataApiHook-example
的修改版本。通过它,我连接了两个按钮,然后为我提供了三种查询端点的方法。我选择在所有情况下都使用相同的端点,但是已经在不同的端点上对其进行了测试,并且看起来工作正常。
import React, {
Fragment,
useState,
useEffect,
useReducer,
} from 'react';
import axios from 'axios';
const dataFetchReducer = (state, action) => {
switch (action.type) {
case 'FETCH_INIT':
return { ...state, isLoading: true, isError: false };
case 'FETCH_SUCCESS':
return {
...state,
isLoading: false,
isError: false,
data: action.payload,
};
case 'FETCH_FAILURE':
return {
...state,
isLoading: false,
isError: true,
};
default:
throw new Error();
}
};
export const useDataApi = (initialUrl, initialData) => {
console.log('Starting useDataApi');
const [url, setUrl] = useState(initialUrl);
const [state, dispatch] = useReducer(dataFetchReducer, {
isLoading: false,
isError: false,
data: initialData,
});
useEffect(() => {
let didCancel = false;
const fetchData = async () => {
console.log('Dispatching FETCH_INIT');
dispatch({ type: 'FETCH_INIT' });
try {
const result = await axios(url);
if (!didCancel) {
console.log('Dispatching FETCH_SUCCESS');
dispatch({ type: 'FETCH_SUCCESS', payload: result.data });
}
} catch (error) {
if (!didCancel) {
console.log('Dispatching FETCH_FAILURE');
dispatch({ type: 'FETCH_FAILURE' });
}
}
};
fetchData();
return () => {
didCancel = true;
};
}, [url]);
return [state, setUrl];
};
function App() {
const [query, setQuery] = useState('redux');
const [{ data, isLoading, isError }, doFetch] = useDataApi(
'http://hn.algolia.com/api/v1/search?query=redux',
{ hits: [] },
);
const handleTestButton1Click = (event) => {
console.log('Test Button 1 pressed');
doFetch(
'http://hn.algolia.com/api/v1/search?query=canada',
);
};
const handleTestButton2Click = (event) => {
console.log('Test Button 2 pressed');
doFetch(
'http://hn.algolia.com/api/v1/search?query=germany',
);
};
return (
<Fragment>
<form
onSubmit={event => {
doFetch(
`http://hn.algolia.com/api/v1/search?query=${query}`,
);
event.preventDefault();
}}
>
<input
type="text"
value={query}
onChange={event => setQuery(event.target.value)}
/>
<button type="submit">Search</button>
</form>
<div>
<button type="button" onClick={() => handleTestButton1Click()}>Test 1</button>
<button type="button" onClick={() => handleTestButton2Click()}>Test 2</button>
</div>
{isError && <div>Something went wrong ...</div>}
{isLoading ? (
<div>Loading ...</div>
) : (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
)}
</Fragment>
);
}
export default App;
我有几个问题:
data
填充的新doFetch
?如果问题2不清楚,请换一种说法:在所有情况下,data
对象都由useDataApi
填充。但是,如果对useDataApi
的第一次调用是为了填充某物,第二次调用是为了填充其他东西,而第三次调用是为了填充其他东西,那么处理这种逻辑的最佳方法是什么?
答案 0 :(得分:1)
假设我不想在组件加载时调用查询(也不想在加载时发出GET请求)。那怎么办?
您可以将一个空字符串传递给您的钩子,并创建一个当API端点为空时不触发获取的条件:
// I've removed initialUrl
export const useDataApi = (initialData) => {
console.log('Starting useDataApi');
const [url, setUrl] = useState('');
const [state, dispatch] = useReducer(dataFetchReducer, {
isLoading: false,
isError: false,
data: initialData,
});
useEffect(() => {
if (!url) {
return;
}
let didCancel = false;
...
}, [url]);
return [state, setUrl];
}
想象一下,由按钮1和2触发的事件实际上是每个对不同API端点的调用。例如,按钮1可以代表一个调用,以查明是否存在刚刚输入的特定用户名。按钮2可以代表一个呼叫,以查明是否刚刚输入的电子邮件地址已经存在。在这种情况下,通常的做法是确保正确使用doFetch填充的新数据?
由您决定。以我的观点,高级部分处理您已经做过的新数据:使用化简器。我考虑将data
填充为一个对象,其中每个属性都是每个API响应的ID。我的意思是,如果所有API都返回一个字段type
,我将使用它通过这种方式保存数据:
const type = ... // get type from payload
const { data } = state;
// if you want to replace old data
data[type] = action.payload;
// if you want to append new data
data[type].push(action.payload)
return {
...state,
isLoading: false,
isError: false,
data,
};