React组件中react-loader-spinner不显示:请求时无加载状态
解决react-loader-spinner在API请求期间不显示的问题
你的代码核心问题是加载状态的设置时机完全颠倒,导致加载动画永远不会在请求等待阶段显示:
- 你在API请求完成的
then回调里才把isLoading设为true,这时候请求已经结束,加载动画根本没机会出现 - 当前
isLoading为true时,组件只返回加载动画,但这时候请求已经完成,逻辑完全反了
修正步骤:
- 发起请求前立即设置加载状态:在调用
openai.createCompletion之前,先通过setState把isLoading设为true,触发加载动画显示 - 请求结束后关闭加载状态:在
then(请求成功)和catch(请求失败)回调里,把isLoading设为false,同时更新数据或处理错误 - 错误处理:添加
catch捕获请求异常,避免请求失败后页面一直处于加载状态
修改后的完整代码:
import React from "react"; import { Component} from "react"; import { Container, Form, Button, Card, FormGroup, FormLabel, FormControl } from 'react-bootstrap' import { ThreeDots } from 'react-loader-spinner' const { Configuration, OpenAIApi } = require('openai'); class AppGenerator extends Component { constructor() { super() this.state = { isLoading: false, heading: '', response: '', error: '' // 新增错误状态,用于显示请求失败信息 } } onFormSubmit = async e => { e.preventDefault() const formData = new FormData(e.target), formDataObj = Object.fromEntries(formData.entries()) console.log(formDataObj.suggestion) // 修改点1:发起请求前设置加载状态为true this.setState({ isLoading: true, error: '' }); const configuration = new Configuration({ apiKey: 'somekey', }); const openai = new OpenAIApi(configuration); openai.createCompletion({ model: 'text-davinci-003', prompt: `Write the blog about ${formDataObj.suggestion} and be very specific about it with a minimum of 1500 words`, temperature: 1, max_tokens: 2000, top_p: 1, frequency_penalty: 0, presence_penalty:0, }) .then((response) => { // 修改点2:请求成功后关闭加载状态,更新数据 this.setState({ isLoading: false, heading: `Suggestion for: ${formDataObj.suggestion}`, response: `${response.data.choices[0].text}`, }) }) // 修改点3:添加错误捕获,关闭加载状态并记录错误信息 .catch((err) => { this.setState({ isLoading: false, error: '请求失败,请稍后重试' }); console.error('API请求错误:', err); }); } render() { const {isLoading, heading, response, error} = this.state; if (isLoading) { return <ThreeDots height="80" width="80" radius="9" color="green" ariaLabel="loading"/> } return( <div> <Container> <br/> <h2 style={{color: '#fff'}}>Blog Post Suggestion</h2> <br/> <Form onSubmit={this.onFormSubmit}> <FormGroup className="mb-3" controlId="formBasicEmail"> <FormLabel style={{color: '#fff'}}>What would you us to write about?</FormLabel> <FormControl type = 'text' name = 'suggestion' placeholder= 'ie: How artificial intelligence will change the world' /> <Form.Text className="text-muted"> Enter as much information as possible. </Form.Text> </FormGroup> <Button id="button" variant="primary" size='lg' type="submit" className="button-submit"> Create Blog Post </Button> </Form> {/* 显示错误信息 */} {error && <p style={{color: 'red', marginTop: '1rem'}}>{error}</p>} <br/> <br/> <Card style={{border: 'none'}}> <Card.Body style={{background: '#212529'}}> <Card.Title style={{color: '#fff', background: '#212529'}}><h2>{heading}</h2></Card.Title> <br/> <Card.Text style={{color: '#fff', background: '#212529'}}><p>{response}</p></Card.Text> </Card.Body> </Card> </Container> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> </div> ) } } export default AppGenerator
可选优化:
如果不想在加载时替换整个页面,可以把加载动画嵌入到页面中(比如按钮位置或结果区域),而不是直接返回加载组件。例如修改render部分:
render() { const {isLoading, heading, response, error} = this.state; return( <div> <Container> <br/> <h2 style={{color: '#fff'}}>Blog Post Suggestion</h2> <br/> <Form onSubmit={this.onFormSubmit}> <FormGroup className="mb-3" controlId="formBasicEmail"> <FormLabel style={{color: '#fff'}}>What would you us to write about?</FormLabel> <FormControl type = 'text' name = 'suggestion' placeholder= 'ie: How artificial intelligence will change the world' disabled={isLoading} // 加载时禁用输入框 /> <Form.Text className="text-muted"> Enter as much information as possible. </Form.Text> </FormGroup> <Button id="button" variant="primary" size='lg' type="submit" className="button-submit" disabled={isLoading} // 加载时禁用按钮,防止重复提交 > {isLoading ? <ThreeDots height="20" width="20" radius="3" color="#fff" ariaLabel="loading"/> : 'Create Blog Post'} </Button> </Form> {error && <p style={{color: 'red', marginTop: '1rem'}}>{error}</p>} <br/> <br/> {isLoading ? ( <div style={{display: 'flex', justifyContent: 'center', padding: '2rem'}}> <ThreeDots height="80" width="80" radius="9" color="green" ariaLabel="loading"/> </div> ) : ( <Card style={{border: 'none'}}> <Card.Body style={{background: '#212529'}}> <Card.Title style={{color: '#fff', background: '#212529'}}><h2>{heading}</h2></Card.Title> <br/> <Card.Text style={{color: '#fff', background: '#212529'}}><p>{response}</p></Card.Text> </Card.Body> </Card> )} </Container> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> </div> ) }
内容的提问来源于stack exchange,提问作者DZR
相关产品推荐
相关产品推荐

