react-ajax:组件接收到数据后,在render函数内return jsx模板:渲染数据列表,会出现报错,页面无法显示

原因:组件还没有render因为ajax是异步的而render第一次更新获取不到数据。

AJAX通常是一个异步请求,也就是说,即使componentDidMount函数调用完毕,数据也不会马上就获得,浏览器会在数据完全到达后才调用AJAX中所设定的回调函数,有时间差。因此当响应数据、更新state前,需要先通过this.isMounted() 来检测组件的状态是否已经mounted。

解决:

在jsx内加入判断,在满足条件的情况下渲染即可

 {test instanceof Array?'数组':"不是数组"}

 {
                   test instanceof Array
                   ?
                   (
                   <div>
                      {
                           test.map((v,i)=>{
                            return(
                            <div key={i}>{v.name}</div>
                            )
                        })
                      }
                   </div>)
                   :
                   (
                       <div>
                           
                       </div>
                   )
               }

错误代码:

 {/* {
                           test.map((v,i)=>{
                            return(
                            <div key={i}>{v.name}</div>
                            )
                        })
                      }
                   不带判断报错信息:   Cannot read property 'map' of null */}

注意不要这样判断:

test.length>0或test.length 页面都无发正常显示并报错

改成在jsx内这样判断: test instanceof Array页面就成功显示了

 

解决二:在render函数内return前线判断

例如:

render() {
                const {repName,repUrl} = this.state;
                if(!repName){
                    return <h2>LOADING...</h2>
                }else{
                    return <h2>Most star repo is <a href={repUrl}>{repName}</a></h2>
                }
            }

 

 

扩展:

扩展:在React组件中如何通过AJAX请求来加载数据呢?

首先,AJAX请求的源URL应该通过props传入;其次,最好在componentDidMount函数中加载数据。加载成功,将数据存储在state中后,通过调用setState来触发渲染更新界面。

一般将数据请求Ajax方法写在组件的hook函数componentDidMount 中,这样一旦页面加载完毕就开始执行Ajax函数。
从服务端获取数据库可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。
当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。

对于同步的状态改变,是可以放在componentWillMount,对于异步的,最好好放在componentDidMount。

 参考代码:

import React from 'react'
import {Form,Select,Button,Upload,Radio,DatePicker} from 'antd'
//日期中文
import 'moment/locale/zh-cn';
import locale from 'antd/es/date-picker/locale/zh_CN';
import axios from 'axios'//引入axios
const { RangePicker } = DatePicker;
const layout = {
    labelCol: { span: 6 },
    wrapperCol: { span: 12 },
};
const labelCol={
    span: 3, offset: 12
}
const validateMessages = {
    required: '${label} 不能为空!',//必选规则
    types: {
      email: '${label} is not validate email!',
      number: '${label} is not a validate number!',
    },
    number: {
      range: '${label} 必须在 ${min} 和 ${max}之间',
    },
};
//绑定上传的date
const normFile = e => {//这个很重要,如果没有将上传失败并报错
    console.log('Upload event:', e);
    if (Array.isArray(e)) {
      return e;
    }
    return e && e.fileList;
    };
    // -------------------------------------------------------------------------------------------------------------
class FormMonth extends React.Component{
    constructor(props){
        super(props)
        this.state={
            test:null,
            test2:[1,2,3]
        }
    }
    formRef = React.createRef();
    onFill = () => {//给选择框等设置默认值
        this.formRef.current.setFieldsValue({
            jiemu:'节目一',
            reapeat:'每天',
            onJiemu:'是'
        })
        console.log(this.formRef.current.getFieldValue())//这里能够获取到初始化挂载的值
    };
    //ajax---------------------------------------------
    ajaxhostServe=()=>{//服务器请求
        // 涉及到跨域问题,要在开发环境中,想要正常访问到8000端口的服务,我们需要代理。
        // 代理的做法是:在项目的package.json文件添加“proxy”属性,并重新运行npm start
        //"browserslist": ...同级下
        // "proxy": "http://localhost:8000"
        //既可访问本地 也可访问新开启的服务器所访问的文件

        // axios.get('/api/users')
        // .then( (response)=> {
        //     // handle success
        //     console.log(response);
        // })
        // .catch( (error)=> {
        //     // handle error
        //     console.log(error);
        // })
        fetch('/api/users').then(res => {
            console.log(res)
            return res.json()
        }).then(data => {
            console.log(data)
            this.setState({test: data})
        })
    }
    ajaxFetch=()=>{//发送的网络请求
        fetch('/static/ajax.json').then(res => {
            console.log(res)
            return res.json()
        }).then(data => {
            console.log(data)
            this.setState({test: data})
        })
    }
    ajaxAxios=()=>{
        axios.get('/static/ajax.json')
        .then( (response)=> {
            // handle success
            console.log(response);
            if(response){
                this.setState({
                    test:response.data
                })
            }
        })
        .catch( (error)=> {
            // handle error
            console.log(error);
        })
    }
    // 周期函数--------------------------------------
    // componentWillMount(){//将要挂载时 请求接口在这里通常
    //     this.ajaxAxios()
    // }
    // componentWillUnmount(){//销毁前 -切换到其它页面组件时会调用
    //    console.log('unmounted')
    // //    console.log(this.state.test)//能够请求到
    // }
    componentDidMount(){//挂载时 获取ref要在这里就可以设置默认值
        // this.ajaxFetch()
        this.onFill()
        this.ajaxAxios()
        // this.ajaxhostServe()//从服务器上面获取的数据
        // console.log(this.state.test)//null 请求不到数据为空
    }
    render(){
        console.log(this.state.test)//能够请求到数据
        // this.onFill()//这时候获取formRef 会报错
        const OptArr=['节目一','节目二','节目三','节目四','节目五','节目六']
        const {Option} = Select
        const onFinish = (v)=>{
            // console.log(v)
            const timer=v['choseTimer']
            const value={
                ...v,
                'choseTimer':[timer[0].format('YYYY-MM-DD h:mm:ss'),timer[1].format('YYYY-MM-DD h:mm:ss')]
            }
            console.log(value)
        }
       const test = this.state.test
        return(
            <div>
                {/* {
                           test.map((v,i)=>{
                            return(
                            <div key={i}>{v.name}</div>
                            )
                        })
                      }
                   不带判断报错信息:   Cannot read property 'map' of null */}
                {/* {test instanceof Array?'数组':"非数组"} */}
               {
                   test instanceof Array
                   ?
                   (
                   <div>
                      {
                           test.map((v,i)=>{
                            return(
                            <div key={i}>{v.name}</div>
                            )
                        })
                      }
                   </div>)
                   :
                   (
                       <div>
                       </div>
                   )
               }
                <Form ref={this.formRef} {...labelCol} {...layout} onFinish={onFinish}>
                    {/* 选择节目 */}
                   <Form.Item name="jiemu" label="节目">
                        <Select>
                            {
                                OptArr.map((v)=>{
                                    return(
                                    <Option key={v} value={v}>{v}</Option>
                                    )
                                })
                            }
                        </Select>
                   </Form.Item>
                   {/* 上传 */}
                   {/* valuePropName="fileList"  getValueFromEvent={normFile}  这两个需同时*/}
                   <Form.Item name="upload"  valuePropName="fileList"  getValueFromEvent={normFile} label="上传">
                   <Upload name="logo" action="/upload.do" listType="picture">
                        <Button>添加素材</Button>
                   </Upload>
                   </Form.Item>
                   {/* 重复 */}
                   <Form.Item label="重复" name="reapeat">
                      <Radio.Group>
                        <Radio value="每天">每天</Radio>
                        <Radio value="每周">每周</Radio>
                        <Radio value="每月">每月</Radio>
                        <Radio value="特别日">特别日</Radio>
                        <Radio value="自定义">自定义</Radio>
                      </Radio.Group>
                    </Form.Item> 
                    {/*开机节目*/}
                    <Form.Item label="开机节目" name="onJiemu">
                                <Radio.Group>
                                    <Radio value="是">是</Radio>
                                    <Radio value="否">否</Radio>
                                </Radio.Group>
                    </Form.Item>
                    {/*日期选择*/}
                    <Form.Item label='日期选择' name='choseTimer'>
                        <RangePicker locale={locale} showTime></RangePicker>
                    </Form.Item>
                    {/*提交*/}
                    <Form.Item
                    wrapperCol={{ ...layout.wrapperCol, offset: 6 }}>
                        <Button type='primary' htmlType="submit">提交</Button>
                    </Form.Item>
                </Form>
            </div>
        )
    }
}
export default FormMonth

 

posted @ 2020-09-03 14:14  少哨兵  阅读(648)  评论(0编辑  收藏  举报