Issues
- 我无法打电话
useFetchMyApi
在事件处理程序中,因为它违反了钩子规则。
正确的,react hooks只能从功能组件和其他react hooks的主体中调用。它们不能有条件地调用,例如在异步回调或循环中。
- 如何根据响应刷新项目列表
useFetchMyApi
?
你里面什么都没有App
触发重新渲染,触发效果,从而触发效果的回调。
Solution
您应该利用useEffect
钩子在您的自定义中的依赖关系useFetchMyApi
用于刷新项目列表的钩子。添加一些本地组件状态来表示“当前”选定的位置。使用您的按钮onClick
回调以更新状态并触发重新渲染,然后重新运行您的自定义挂钩。
const useFetchMyApi = (location = "") => {
const [items, setItems] = useState([]);
useEffect(() => {
// let's stimulate the API call with a 2 seconds response time
setTimeout(() => setItems([location, Math.random()]), 2000);
}, [location]); // <-- effect callback triggers when location updates
return { items };
};
function App() {
const locationSelect = useRef(null);
const [location, setLocation] = useState("mylocation1"); // <-- add state
const { items } = useFetchMyApi(location); // <-- pass location value to hook
const onButtonClicked = () => {
const selectedLocation = locationSelect.current.value;
setLocation(selectedLocation); // <-- update state, trigger rerender
};
return (
<div className="App">
<select ref={locationSelect}>
<option value="location1">Location 1</option>
<option value="location2">Location 2</option>
</select>
<button onClick={onButtonClicked}>Refresh</button>
<ul>
{items.map((item) => (
<li>{item}</li>
))}
</ul>
</div>
);
}
替代解决方案
另一种解决方案是重写您的自定义useFetchMyApi
钩子还返回一个回调,以便在单击处理程序中按需调用以执行获取和更新列表。这是一个简单的转换。请注意,现在返回的 fetch 函数消耗该位置,而不是挂钩调用。
const useFetchMyApi = () => {
const [items, setItems] = useState([]);
// custom fetch function consumes location
const locationFetch = (location = "") => {
// let's stimulate the API call with a 2 seconds response time
setTimeout(() => setItems([location, Math.random()]), 2000);
};
return [items, locationFetch]; // <-- return state and fetch function
};
export default function App() {
const locationSelect = useRef(null);
const [items, locationFetch] = useFetchMyApi(); // <-- destructure state and fetch function
useEffect(() => {
locationFetch("mylocation1");
}, []); // <-- initial mounting fetch call
const onButtonClicked = () => {
const selectedLocation = locationSelect.current.value;
locationFetch(selectedLocation); // <-- invoke fetch function
};
return (
<div className="App">
<select ref={locationSelect}>
<option value="location1">Location 1</option>
<option value="location2">Location 2</option>
</select>
<button onClick={onButtonClicked}>Refresh</button>
<ul>
{items.map((item) => (
<li>{item}</li>
))}
</ul>
</div>
);
}