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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM