你说我一个后端工程师,咋前端一写就是好几个月呢 —— UlyC
前端问题记录
新项目没招前端,没想到全包给我了,踏上前端不归路啊。。。这里是一些碰到的浪费了许多时间的问题记录。
1. POST请求参数丢失
描述
this.props.dispatch({
type: 'create/createTask',
payload: {
task_name: "演练",
task_ips: eipCount.toString(),
igw_ip: ip,
region: region,
region_id: regionID,
region_short: regionShortID,
zone: zone,
status: "1",
flow: level.toString(),
clean_flag: this.state.autoDestroy,
// CPU: CPU,
// Mbps: Mbps,
// storage: storage,
simu_ips:freeEipCount.toString(),
},
},
);
simu_ips:freeEipCount.toString()
放在最后一行时POST请求发送出现问题,前端可以看到发送的body中含有simu_ips
字段,但是服务器端无法获取此字段。(抓包也无此字段)
解决
simu_ips:freeEipCount.toString()
只要不置于body最后一行,请求都是正确的。原因暂时未知。
2.chrome 开发者工具观察响应 Failed to load response data
在前端更改 window.location 做跳转,想在 chrome 开发者工具中观察跳转之前发的一个 xhr 请求,勾上了 Preserve log,发现请求是 200 status code,但是 Response 是 Failed to load response data。
原来是 chrome 的一个 Bug: https://stackoverflow.com/a/38925237
解决方法也在链接里提到,
This is a known issue, that’s been around for a while, and debated a lot. However, there is a workaround, in which you pause on onunload, so you can view the response before it navigates away, and thereby doesn’t lose the data upon navigating away.
3. 表单拆分
React使用表单时,主要遇到的问题是:
- Field太多导致的卡顿问题
- 拆分Form后所有子表单值的获取
最初写法是,
render(){
const {form} = this.props;
reurn<Form form={form} >
{console.log(form.getFieldsValue())}
<RegionSelect form={form}/>
<InstanceConfig form={form}/>
<GateWayConfig form={form} cardsList={this.props.cardsList}/>
<AutomationConfig form={form}/>
</Form>}
每个子组件的值状态提升至父组件的Form中,但是这么写耦合性太强,导致性能十分低下。
后来将每个子组件都拆为各自独立的表单,需要获取数据时,使用getFieldsValue
方法取到,性能提升不少。
getAllFieldsValue=() =>{
this.setState(this.formA.getFieldsValue());
this.setState(this.formB.getFieldsValue());
this.setState(this.formC.getFieldsValue());
this.setState(this.formD.getFieldsValue());
};
render(){
return <div>
<RegionSelect ref={formA => {this.formA = formA}}/>
<InstanceConfig ref={formB => {this.formB = formB}}/>
<GateWayConfig ref={formC => {this.formC = formC}} />
<AutomationConfig ref={formD => {this.formD = formD}}/>
</div>}
4.使用umi的mock数据
若是同一api,请求的动作不同,得不到后面的数据,状如:
'POST /drill/task/hosts': {status: 0},
'GET /drill/task/hosts': {"message":[{"ID":1,"CreatedAt":"2018-12-14T01:55:40+08:00","UpdatedAt":"2019-01-02T20:04:49+08:00",
"DeletedAt":null,"Task_id":"226600110560135937",}]}
```,
调了一晚上。。发现是umi mock数据的坑,最后用第三方mock调试是正确的。
5.dva-loading用法
dva-loading是dvajs的一个插件,封装了对loading状态的处理。它提供了对当前异步加载方法的状态(异步加载中状态为 true,异步加载完成状态为 false)的监听和追踪, 可以用来设定ant design中的组件的loading属性。
用法
//index.js
import dva from 'dva';
import createLoading from 'dva-loading';
const app = dva();
app.use(createLoading());
// yourfile.js
class Foo extends Component {
render() {
const {isLoading} = this.props;
return <div>
<Table loading={isLoading}>
</div>
}
function mapStateToProps(state) {
return {
//dva-loading 有effects, models,global三个方法
isLoading: state.loading.effects['Name[namespace]/Name[*effect]'],
// 意为 根据namespace中的某个动作来决定isLoading状态
// 或者 isLoading: state.loading.models.Name[filename],
//意为 根据models的某个文件 来决定isLoading状态
// 或者 isLoading: state.loading.global
//当所有异步请求都响应才做下一步操作,该方法监听所有异步请求的状态。
};
}
6. dva路由监听
在dva中我们可以在Modal中实现事件监听,通过在modal中添加一个 subscriptions,并且在里面创建一个setup函数
{
namespace: 'infoArea',
state: {
subscriptions: {
setup ({dispatch, history}) {
history.listen(( pathname ) => {
console.log(pathname)
})
},
effects: {
},
reducers: {
},
这个set函数只接受两个参数,一个是dispatch一个是history.
监听时经常需要动态匹配路由,这时我们需要 path-to-regexp这个包,可以自己npm install一下。
这个包的一般用法就是像这样
subscriptions: {
setup({history, dispatch}) {
// 监听 history 变化,当进入 `/info/A|B` 时触发 `queryOverview` action
return history.listen((location) => {
const match = pathToRegexp('/info/:name').exec(location.pathname);
//match是一个数组,match[0]为匹配到所有的东西,match[1]才是需要的精确匹配数据
if (match) {
let name = match[1];
let id = location.query.id;
dispatch({
type: 'queryOverview',
name:name,
payload: id,
});
}
});
},
},
更详细的用法见