原因:组件还没有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