前端React笔记

哭了

Posted by UlyC on January 28, 2019

你说我一个后端工程师,咋前端一写就是好几个月呢 —— 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使用表单时,主要遇到的问题是:

  1. Field太多导致的卡顿问题
  2. 拆分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,
                    });
                }
            });
        },
    },

更详细的用法见


知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。