原因:組件還沒有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