在尝试学习全栈开发时,我尝试了本教程(https://www.freecodecamp.org/news/create-a-react-frontend-a-node-express-backend-and-connect-them-together-c5798926047c/(。然而,它是使用功能组件而不是钩子编写的。我正在尝试将此部分转换为挂钩:
constructor(props) {
super(props);
this.state = { apiResponse: "" };
}
callAPI() {
fetch("http://localhost:9000/testAPI")
.then(res => res.text())
.then(res => this.setState({ apiResponse: res }));
}
componentWillMount() {
this.callAPI();
}
在渲染部分有这个:
<p className="App-intro">;{this.state.apiResponse}</p>
我试过这个:
const [apiResponse, setApiResponse] = useState();
useEffect(() => {
const fetchApiResponse = async () => {
const result = await (
'http://localhost:9000/testAPI'
);
setApiResponse(result);
console.log("apiResponse " + apiResponse);
};
fetchApiResponse();
});
但是apiResponse的console.log总是显示为未定义。我知道我一定做错了什么,但我想不通。
您的尝试并不遥远。
有两个问题:
问题1.
为了获得与componentWillMount
相同的效果(附带说明-这是一种不推荐使用的方法,请使用componentDidMount
或constructor
(,您需要告诉useEffect
在装载时只运行一次。为此,您给它一个空的依赖项数组。
useEffect(() => {
// do stuff
}, []); // empty array as second argument
通过不提供第二个参数,效果将在每次渲染时运行。
问题2.
状态更新是异步的。这意味着您不能在更新日志apiResponse
后立即对其进行控制台操作,并期望它包含新值。
为了解决这个问题,只需在钩子外的函数体中使用console.log。
下面是一个简化的例子:
const {useState, useEffect} = React;
const Example = () => {
const [apiResponse, setApiResponse] = useState();
useEffect(() => {
const fetchApiResponse = () => {
const result = 'test';
setApiResponse(result);
// Will not be updated
console.log("wrong: apiResponse ", apiResponse);
}
fetchApiResponse();
}, []);
// Will be updated
console.log("right: apiResponse ", apiResponse);
return <span />
}
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>