please explain the error to me, Error: Rendered more hooks than during the previous render
please explain the error to me, Error: Rendered more hooks than during the previous render
我是新手,现在正在学习制作自定义 React 挂钩
在这里,我试图调用我在 app.js 文件中创建的函数,我想在单击按钮时使用它。但没有这样做。请帮我找出错误并理解它。
import React, {
useEffect,
useState
} from "react";
const useRandomJoke = () => {
const [jokes, setJokes] = useState();
useEffect(() => {
const jokeFetch = async() => {
await fetch("https://api.icndb.com/jokes/random")
//we'll run 2 "then"
.then(
// this will give us response and will return inform of res.json
(res) => res.json()
) //.json is a format
.then((data) => {
setJokes(data.value.joke);
}); // now calling data from te returned values in res.json
};
jokeFetch();
}, []);
return jokes;
};
export default useRandomJoke;
//With onClick function
function App() { const [jokes, setJokes] = useState();
return (
<div className="App">
<h1>Random Jokes</h1>
<p>{jokes}</p>
<button onClick={()=>{setJokes(useRandomJoke)}}>
Click for Jokes</button>
</div>
); } export default App;
`
useRandomJoke
是自定义挂钩。挂钩只能在组件的顶层调用,并且由于自定义挂钩已经具有 joke
状态,因此您不需要在 App
组件中添加其他状态。
如果您想在组件呈现后以及每次单击按钮时获得一个新笑话,您可以这样做:
const useRandomJoke = () => {
const [joke, setJoke] = useState("");
const fetchJoke = useCallback(() => {
fetch("https://api.icndb.com/jokes/random")
.then((res) => res.json())
.then((data) => {
setJoke(data.value.joke);
});
}, []);
return [joke, fetchJoke];
};
export default function App() {
const [joke, fetchJoke] = useRandomJoke();
useEffect(() => {
fetchJoke();
}, [fetchJoke]);
return (
<div className="App">
<h1>Random Jokes</h1>
<p>{joke}</p>
<button onClick={fetchJoke}>Click for a random joke</button>
</div>
);
}
您不能有条件地调用 React 挂钩,就像在按钮的 onClick
处理程序中一样,因为这会破坏 rules of hooks。我建议将 useRandomJoke
钩子重构为 return 获取的笑话 和 获取下一个随机笑话的函数。您也不应该将 async/await
与 Promise 链混合使用,因为这是一种反模式。
const useRandomJoke = () => {
const [jokes, setJokes] = useState(null);
const jokeFetch = async () => {
const res = await fetch("https://api.icndb.com/jokes/random");
const data = await res.json();
setJokes(data.value.joke)
};
return [jokes, jokeFetch];
};
然后在应用程序中使用挂钩。
function App() {
const [joke, getJoke] = useRandomJoke();
return (
<div className="App">
<h1>Random Jokes</h1>
<p>{joke}</p>
<button onClick={getJoke}>Click for Joke</button>
</div>
);
}
嗯,这里要讲的不止一点:
1-在React.js中,你只能在函数体的顶层调用自定义钩子(react 将任何以关键字 use
开头的函数识别为钩子)
function App() {
// top level is here
const randomJokes = useRandomJoke()
const [jokes, setJokes] = useState();
return (
<div className="App">
<h1>Random Jokes</h1>
<p>{jokes}</p>
<button onClick={()=>{setJokes(useRandomJoke)}}>
Click for Jokes
</button>
</div>
); }
export default App;
2- 在您的示例中,我知道您想在每次 onClick
触发时都有一个新笑话,为了做到这一点,我认为使用自定义挂钩不是理想的解决方案,因为您的自定义挂钩仅在初始渲染时运行 fetchJokes
方法一次(如您在 useEffect
挂钩中所述),我知道很多人提到 useEffect
是制作 API 调用,但它不一定适用于所有用例,在您的示例中很简单,您不必使用 useEffect
也不必创建自定义挂钩。
一个可能的简单解决方案:
function App() {
// we always call hooks at the top level of our function
const [jokes, setJokes] = useState();
const fetchNewJoke = () => {
fetch("https://api.icndb.com/jokes/random")
//we'll run 2 "then"
.then(
// this will give us response and will return inform of
res.json
(res) => res.json()
) //.json is a format
.then((data) => {
setJokes(data.value.joke);
}); // now calling data from te returned values in res.json
};
};
return (
<div className="App">
<h1>Random Jokes</h1>
<p>{jokes}</p>
<button onClick={fetchNewJoke}>Click for Joke</button>
</div>
);
} export default App;
我是新手,现在正在学习制作自定义 React 挂钩 在这里,我试图调用我在 app.js 文件中创建的函数,我想在单击按钮时使用它。但没有这样做。请帮我找出错误并理解它。
import React, {
useEffect,
useState
} from "react";
const useRandomJoke = () => {
const [jokes, setJokes] = useState();
useEffect(() => {
const jokeFetch = async() => {
await fetch("https://api.icndb.com/jokes/random")
//we'll run 2 "then"
.then(
// this will give us response and will return inform of res.json
(res) => res.json()
) //.json is a format
.then((data) => {
setJokes(data.value.joke);
}); // now calling data from te returned values in res.json
};
jokeFetch();
}, []);
return jokes;
};
export default useRandomJoke;
//With onClick function
function App() { const [jokes, setJokes] = useState();
return (
<div className="App">
<h1>Random Jokes</h1>
<p>{jokes}</p>
<button onClick={()=>{setJokes(useRandomJoke)}}>
Click for Jokes</button>
</div>
); } export default App;
`
useRandomJoke
是自定义挂钩。挂钩只能在组件的顶层调用,并且由于自定义挂钩已经具有 joke
状态,因此您不需要在 App
组件中添加其他状态。
如果您想在组件呈现后以及每次单击按钮时获得一个新笑话,您可以这样做:
const useRandomJoke = () => {
const [joke, setJoke] = useState("");
const fetchJoke = useCallback(() => {
fetch("https://api.icndb.com/jokes/random")
.then((res) => res.json())
.then((data) => {
setJoke(data.value.joke);
});
}, []);
return [joke, fetchJoke];
};
export default function App() {
const [joke, fetchJoke] = useRandomJoke();
useEffect(() => {
fetchJoke();
}, [fetchJoke]);
return (
<div className="App">
<h1>Random Jokes</h1>
<p>{joke}</p>
<button onClick={fetchJoke}>Click for a random joke</button>
</div>
);
}
您不能有条件地调用 React 挂钩,就像在按钮的 onClick
处理程序中一样,因为这会破坏 rules of hooks。我建议将 useRandomJoke
钩子重构为 return 获取的笑话 和 获取下一个随机笑话的函数。您也不应该将 async/await
与 Promise 链混合使用,因为这是一种反模式。
const useRandomJoke = () => {
const [jokes, setJokes] = useState(null);
const jokeFetch = async () => {
const res = await fetch("https://api.icndb.com/jokes/random");
const data = await res.json();
setJokes(data.value.joke)
};
return [jokes, jokeFetch];
};
然后在应用程序中使用挂钩。
function App() {
const [joke, getJoke] = useRandomJoke();
return (
<div className="App">
<h1>Random Jokes</h1>
<p>{joke}</p>
<button onClick={getJoke}>Click for Joke</button>
</div>
);
}
嗯,这里要讲的不止一点:
1-在React.js中,你只能在函数体的顶层调用自定义钩子(react 将任何以关键字 use
开头的函数识别为钩子)
function App() {
// top level is here
const randomJokes = useRandomJoke()
const [jokes, setJokes] = useState();
return (
<div className="App">
<h1>Random Jokes</h1>
<p>{jokes}</p>
<button onClick={()=>{setJokes(useRandomJoke)}}>
Click for Jokes
</button>
</div>
); }
export default App;
2- 在您的示例中,我知道您想在每次 onClick
触发时都有一个新笑话,为了做到这一点,我认为使用自定义挂钩不是理想的解决方案,因为您的自定义挂钩仅在初始渲染时运行 fetchJokes
方法一次(如您在 useEffect
挂钩中所述),我知道很多人提到 useEffect
是制作 API 调用,但它不一定适用于所有用例,在您的示例中很简单,您不必使用 useEffect
也不必创建自定义挂钩。
一个可能的简单解决方案:
function App() {
// we always call hooks at the top level of our function
const [jokes, setJokes] = useState();
const fetchNewJoke = () => {
fetch("https://api.icndb.com/jokes/random")
//we'll run 2 "then"
.then(
// this will give us response and will return inform of
res.json
(res) => res.json()
) //.json is a format
.then((data) => {
setJokes(data.value.joke);
}); // now calling data from te returned values in res.json
};
};
return (
<div className="App">
<h1>Random Jokes</h1>
<p>{jokes}</p>
<button onClick={fetchNewJoke}>Click for Joke</button>
</div>
);
} export default App;