如何在包含 useEffect 和 useReducer 的点击事件上使用自定义钩子?
How to use the custom hook on click event which contains useEffect and useReducer?
我正在使用包含用于 API 调用的 useEffect 和 useReducer 的自定义挂钩,我在单击按钮时调用此自定义挂钩,但出现此错误(React Hook“useAuth”在函数“handleClick”中被调用既不是 React 函数组件也不是自定义 React Hook 函数)。
代码如下
useAuth.js
import axios from 'axios'
import {useEffect,useReducer} from 'react'
const ACTION = {
LOADING:'loading',
SUCCESS:'success',
ERROR:'error'
}
function reducer(state,action) {
switch (action) {
case ACTION.LOADING:
return {loading:true,data:[]}
case ACTION.SUCCESS:
return {...state,loading:false,data:action.payload.data}
case ACTION.ERROR:
return {...state,loading:false,data:[],error:action.payload.error}
default:
break;
}
}
function useAuth (data) {
const [state, dispatch] = useReducer(reducer, {data:[],loading:true})
useEffect(() => {
dispatch({type:ACTION.LOADING})
const getData = async ()=>{
try {
const response = await axios.post('https://expamle.com',data)
dispatch({type:ACTION.SUCCESS,payload:{data:response.data.data}})
} catch (error) {
dispatch({type:ACTION.ERROR,payload:{data:error.response}})
}
}
getData()
}, [])
return state
}
export default useAuth
app.js
import logo from './logo.svg';
import './App.css';
import useAuth from './useAuth'
function App() {
// const {loading,data,error} = useAuth()
const handleClick = () => {
const {loading,data,error} = useAuth() // how to use custom hook on click event
}
return (
<div className="App">
<button onClick={handleClick}></button>
</div>
);
}
export default App;
理想情况下应该这样写
import logo from './logo.svg';
import './App.css';
import useAuth from './useAuth'
function App() {
const { loading , data ,error, dispatch} = useAuth()
const handleClick = () => {
dispatch({type:'USER_CLICKED'})
console.log('check for your data', data)
}
return (
<div className="App">
<button onClick={handleClick}></button>
</div>
);
}
在您的 useAuth 挂钩中,您应该有一个在单击按钮时变为 true 的标志
const ACTION = {
LOADING:'loading',
SUCCESS:'success',
ERROR:'error'
}
function reducer(state,action) {
switch (action) {
case ACTION.USER_CLICK:
return {...state, userClicked: true}
case ACTION.LOADING:
return {loading:true,data:[]}
case ACTION.SUCCESS:
return {...state,loading:false,data:action.payload.data}
case ACTION.ERROR:
return {...state,loading:false,data:[],error:action.payload.error}
default:
break;
}
}
function useAuth(data) {
const [state, dispatch] = useReducer(reducer, { data: [], loading: true, userClicked: false });
useEffect(() => {
if (state.userClicked) {
dispatch({ type: ACTION.LOADING });
const getData = async () => {
try {
const response = await axios.post("https://expamle.com", data);
dispatch({
type: ACTION.SUCCESS,
payload: { data: response.data.data },
});
} catch (error) {
dispatch({ type: ACTION.ERROR, payload: { data: error.response } });
}
};
getData();
}
}, [userClicked]);
return { state, dispatch };
}
export default useAuth;
useReducer
似乎太多了。我会建议一个简单的 useAsync
,
function useAsync(f, deps) {
const [state, setState] = React.useState({fetching: false})
const [ts, setTs] = React.useState(null)
React.useEffect(_ => {
ts && f()
.then(data => setState({fetching: false, data}))
.catch(error => setState({fetching: false, error}))
}, [...deps, ts])
return [
state,
_ => {
setState({fetching: true, error: null, data: null})
setTs(Date.now())
}
]
}
您可以将 useAsync
用于任何异步行为。现在你可以写 useAuth
,
function useAuth(payload) {
return useAsync(_ => { // ✅ useAsync
return axios.post("https://example.com", payload) // ✅ auth request
}, [payload.username, payload.password])
}
在您的App
、
中使用它
function App() {
const [username, setUsername] = useState("tommy")
const [password, setPassword] = useState("pickle$")
const [{fetching, error, data}, execute] = useAuth({ username, password }) // ✅ useAuth
if (fetching) return <pre>Loading...</pre>
if (error) return <pre>Error: {error.message}</pre>
return <div>
<input value={username} onChange={e => setUsername(e.target.value)} />
<input value={password} onChange={e => setPassword(e.target.value)} />
<button onClick={execute} children="login" /> // ✅ execute
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
}
在 中查看 useAsync
的完整演示。
我正在使用包含用于 API 调用的 useEffect 和 useReducer 的自定义挂钩,我在单击按钮时调用此自定义挂钩,但出现此错误(React Hook“useAuth”在函数“handleClick”中被调用既不是 React 函数组件也不是自定义 React Hook 函数)。 代码如下
useAuth.js
import axios from 'axios'
import {useEffect,useReducer} from 'react'
const ACTION = {
LOADING:'loading',
SUCCESS:'success',
ERROR:'error'
}
function reducer(state,action) {
switch (action) {
case ACTION.LOADING:
return {loading:true,data:[]}
case ACTION.SUCCESS:
return {...state,loading:false,data:action.payload.data}
case ACTION.ERROR:
return {...state,loading:false,data:[],error:action.payload.error}
default:
break;
}
}
function useAuth (data) {
const [state, dispatch] = useReducer(reducer, {data:[],loading:true})
useEffect(() => {
dispatch({type:ACTION.LOADING})
const getData = async ()=>{
try {
const response = await axios.post('https://expamle.com',data)
dispatch({type:ACTION.SUCCESS,payload:{data:response.data.data}})
} catch (error) {
dispatch({type:ACTION.ERROR,payload:{data:error.response}})
}
}
getData()
}, [])
return state
}
export default useAuth
app.js
import logo from './logo.svg';
import './App.css';
import useAuth from './useAuth'
function App() {
// const {loading,data,error} = useAuth()
const handleClick = () => {
const {loading,data,error} = useAuth() // how to use custom hook on click event
}
return (
<div className="App">
<button onClick={handleClick}></button>
</div>
);
}
export default App;
理想情况下应该这样写
import logo from './logo.svg';
import './App.css';
import useAuth from './useAuth'
function App() {
const { loading , data ,error, dispatch} = useAuth()
const handleClick = () => {
dispatch({type:'USER_CLICKED'})
console.log('check for your data', data)
}
return (
<div className="App">
<button onClick={handleClick}></button>
</div>
);
}
在您的 useAuth 挂钩中,您应该有一个在单击按钮时变为 true 的标志
const ACTION = {
LOADING:'loading',
SUCCESS:'success',
ERROR:'error'
}
function reducer(state,action) {
switch (action) {
case ACTION.USER_CLICK:
return {...state, userClicked: true}
case ACTION.LOADING:
return {loading:true,data:[]}
case ACTION.SUCCESS:
return {...state,loading:false,data:action.payload.data}
case ACTION.ERROR:
return {...state,loading:false,data:[],error:action.payload.error}
default:
break;
}
}
function useAuth(data) {
const [state, dispatch] = useReducer(reducer, { data: [], loading: true, userClicked: false });
useEffect(() => {
if (state.userClicked) {
dispatch({ type: ACTION.LOADING });
const getData = async () => {
try {
const response = await axios.post("https://expamle.com", data);
dispatch({
type: ACTION.SUCCESS,
payload: { data: response.data.data },
});
} catch (error) {
dispatch({ type: ACTION.ERROR, payload: { data: error.response } });
}
};
getData();
}
}, [userClicked]);
return { state, dispatch };
}
export default useAuth;
useReducer
似乎太多了。我会建议一个简单的 useAsync
,
function useAsync(f, deps) {
const [state, setState] = React.useState({fetching: false})
const [ts, setTs] = React.useState(null)
React.useEffect(_ => {
ts && f()
.then(data => setState({fetching: false, data}))
.catch(error => setState({fetching: false, error}))
}, [...deps, ts])
return [
state,
_ => {
setState({fetching: true, error: null, data: null})
setTs(Date.now())
}
]
}
您可以将 useAsync
用于任何异步行为。现在你可以写 useAuth
,
function useAuth(payload) {
return useAsync(_ => { // ✅ useAsync
return axios.post("https://example.com", payload) // ✅ auth request
}, [payload.username, payload.password])
}
在您的App
、
function App() {
const [username, setUsername] = useState("tommy")
const [password, setPassword] = useState("pickle$")
const [{fetching, error, data}, execute] = useAuth({ username, password }) // ✅ useAuth
if (fetching) return <pre>Loading...</pre>
if (error) return <pre>Error: {error.message}</pre>
return <div>
<input value={username} onChange={e => setUsername(e.target.value)} />
<input value={password} onChange={e => setPassword(e.target.value)} />
<button onClick={execute} children="login" /> // ✅ execute
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
}
在 useAsync
的完整演示。