Reactjs 在事件处理程序中调用自定义挂钩
我有一个名为Reactjs 在事件处理程序中调用自定义挂钩,reactjs,react-hooks,Reactjs,React Hooks,我有一个名为useFetchMyApi的定制钩子,它将一个获取调用包装到API端点。函数钩子接受一个参数,它包含在post主体中。数据数组输出取决于hook参数 在UI上,应用程序组件调用一次useFetchMyApi。按钮点击处理程序将调用后续的useFetchMyApi,以更新UI上的列表 我的问题: 我无法在事件处理程序中调用useFetchMyApi,因为它违反了hook的规则 如何根据useFetchMyApi的响应刷新项目列表 import React,{useState,useff
useFetchMyApi
的定制钩子,它将一个获取调用包装到API端点。函数钩子接受一个参数,它包含在post主体中。数据数组输出取决于hook参数
在UI上,应用程序组件调用一次useFetchMyApi
。按钮点击处理程序将调用后续的useFetchMyApi
,以更新UI上的列表
我的问题:
useFetchMyApi
,因为它违反了hook的规则useFetchMyApi
的响应刷新项目列表import React,{useState,useffect,useRef}来自“React”;
导入“/styles.css”;
const useFetchMyApi=(location=”“)=>{
const[items,setItems]=useState([]);
useffect(()=>{
//让我们用2秒的响应时间来刺激API调用
setTimeout(()=>setItems([location,Math.random()]),5000);
},[地点];
返回{items};
};
导出默认函数App(){
const locationSelect=useRef(null);
const{items}=useFetchMyApi(“mylocation1”);
const onButtonClicked=(事件)=>{
const selectedLocation=locationSelect.current.value;
//调用api并按位置刷新项目
//在这里修好??
//useFetchMyApi(selectedLocation);
};
返回(
地点1
地点2
刷新
{items.map((item)=>(
- {item}
))}
);
}
问题
useFetchMyApi
,因为它违反了挂钩规则useFetchMyApi
的响应刷新项目列表App
中,您没有任何东西可以触发重新渲染器来触发效果,从而触发效果的回调
解决方案
您应该在自定义useffetchmyapi
hook中利用useffect
hook的依赖项来刷新项目列表。添加一些本地组件状态以表示“当前”选定位置。使用按钮的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>
);
}
为什么不将项目声明为App`state?@thelonglqd项目列表将由自定义挂钩管理,不是吗?不能,您需要修改挂钩以返回执行获取的函数,现在挂钩取决于location参数,而不是onClick事件。感谢您提供的非常有用和详细的解释。状态驱动UI,而不是组件/挂钩。我的错误是认为挂钩可以直接影响其他组件/挂钩。
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>
);
}
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>
);
}