React开发中提升幸福度的一些小技巧

转自React开发中提升幸福度的一些小技巧.md

又一篇来自日常开发的汇总:各位客官请对号入席,店小二逐一上菜。

#第一道菜回锅肉第一道菜:回锅肉

react数组循环,基本都会设置一个唯一的key,表格的对象数组循环一般没什么问题,数据基本都会有一个id。那有种情况就比较坑了,出现在表单形式的页面结构中,对某个数组进行增删改操作,一般对于非对象数组而言,没有id,可能很多人会偷懒,循环的时候,直接设置数组的下标index作为key,当出现增删改时候,就会出现数据对不上或者重新渲染组件的问题等。解决方案有很多种,例如把字符串数组等重组对象数组,每个元素设置一个唯一id等。另外有个方式:推荐使用shortid生成唯一key的数组,和数据数组一起使用,省去提交数据时再重组数组。

importReactfrom'react';
importshortidfrom'shortid';

classDemoextendsReact.Component {
    constructor(props) {
		super(props);
		this.state= {
			data: ['a', 'b', 'c']
		}
		this.dataKeys=this.state.data.map(v=>shortid.generate());
	}
	
    deleteOne=index=> { // 删除操作const { data } =this.state;
        this.setState({ data:data.filter((v, i) => i !== index) });
        this.dataKyes.splice(index, 1);
    }
    
    render() {
	    return (
    	    <ul>
               {
                   data.map((v, i) =><li 
                        onClick={i=>this.deleteOne(i)}  
                        key={this.dataKeys[i]}
                    >
                        {v}
                    </li>
                    )
               } 
            </ul>
	    )
	}
}
// 稍微抽取,可以封装一个通用的组件
复制代码
#第二道菜番茄炒蛋第二道菜:番茄炒蛋

通过判断值是否存在来控制元素是否显示,一般三目运算可以达到此效果,最简单的还是用短路的写法:

// 不错constflag='something';
flag &&<div></div>// 很好// 注意一般可能上面写法多一些,但当flag为0 的时页面上会显示0,用!!将其转为boolean避免坑,// 代码也更规范constflag='something';
!!flag &&<div></div>
复制代码
#第三道菜酸辣土豆丝第三道菜:酸辣土豆丝

使用组件,传递props:

const { data, type, something } =this.state;
<Demo 
    data={data}
    type={type}
    something={something}
/>
复制代码

也许另外一种传递方式更简洁:

const { data, type, something } = this.state;
<Demo 
    {...{ data, id, something }}
/>
复制代码
#第四道菜清炒时蔬第四道菜:清炒时蔬

组件的props有时候会定义很多,但是调用组件传递props的时候又想一个个传,不想一次性传递一个option对象,通过扩展运算符和解构赋值可以简化此操作:

const Demo = ({ prop1, prop2, prop3, ...restProps }) => (
    <div>
        xxxx
        { restProps.something }
    </div>
)
// 父组件使用Demo
<Demo
    prop1={xxx}
    prop2={xxx}
    something={xxx}
/>
复制代码
#第五道菜小吃-糍粑第五道菜:小吃-糍粑

一般改变state值的一种方式:

const { data } =this.state;
this.setState({ data: {...data, key:1 } });
复制代码

另外一种可以通过callback的方式改变state的值

this.setState(({ data }) => ({ data: {...data, key:1 } }));
复制代码

还可以:

this.setState((state, props) => {
    return { counter:state.counter+props.step };
});
复制代码
#第六道菜水煮肉片第六道菜:水煮肉片

React 性能优化有很多种方式,那常见的一种就是在生命周期函数shouldComponentUpdate里面判断某些值或属性来控制组件是否重新再次渲染。

判断一般的字符串,数字或者基础的对象,数组都还是比较好处理,那嵌套的对象或者数组就比较麻烦了,对于这种,可以转成字符串处理,但属性值的位置不同时,那就无效了。

推荐使用lodash(或者其他的类似库)的isEqual对嵌套数组或对象进行判断(相比其他方式更简单些)

shouldComponentUpdate(nextProps, nextState) {
    if (_.isEqual(nextState.columns, this.state.columns)) returnfalse;
    returntrue;
}
复制代码
#第七道菜干锅兔第七道菜:干锅兔

创建弹层的三种方式:

  1. 普通组件通过state和样式控制,在当前组件中显示弹层-每次引入组件并且render里面控制显示,挂载节点在某组件里面

    // 弹层 constDialog= () =>

    弹层
    // 某组件render() { return ( this.state.showDialog&& ) }

2.通过Portals创建通道,在根节点外部挂载组件-但还是需要每次引入并且在render里面调用

// 弹层 classDialogextendsReact.Component {
  constructor(props) {
    super(props);
    this.el=document.createElement('div');
  }
  componentDidMount() {
    modalRoot.appendChild(this.el);
  }
  componentWillUnmount() {
    modalRoot.removeChild(this.el);
  }

  render() {
    returnReactDOM.createPortal(
      this.props.children||<div>xxxx</div>,
      this.el,
    );
  }
}
// 某组件render() {
    return (
        this.state.showDialog&&<Dialog />
    )
}
复制代码

3.推荐使用ReactDom.render创建弹层-挂载根节点外层,使用也更方便

// demolet dialog;
classDialog {
    show(children) {    // 显示this.div=document.createElement('div');
        document.body.appendChild(this.div);

        ReactDom.render(children ||<div>xxxx</div>, this.div);
    }
    destroy() {     // 销毁ReactDom.unmountComponentAtNode(this.div);
        this.div.parentNode.removeChild(this.div);
    }
}
exportdefault {
    show:function(children) {
        dialog =newDialog();
        dialog.show(children);
    },
    hide: xxxxx
};
// 某组件importDialogfrom'xxx';
alert= () => {
    Dialog.show(xxxx);
}
render() {
    return (
        <button onClick={this.alert}>点击弹层</button>
    )
}
复制代码
#第八道菜火烧肉第八道菜:火烧肉

render props是现在很流行的一种渲染方式,通过回调函数,渲染子组件,参数可为父组件的任意属性值(官网也有相应的介绍)新版的contextApi也采用了这个模式。

很多种场景使用此方式的做法:

// 权限控制组件,只需要封装一次connect,// 通过render props向子组件传递权限classAuthWidgetextendsComponent {
    render() {
        returnthis.props.children(this.props.auth);
    }
}

constmapStateToProps=state=> {
    const { auth } = state;
    return { auth:state.auth };
};
exportdefaultconnect(mapStateToProps)(AuthWidget);

// 其他组件使用<AuthWidget
    children={auth=>auth.edit&&<a>编辑</a>}
/>// 使用antd的form时constTest= ({ form, children }) => {
    returnchildren(form);
};
constFormTest=Form.create()(Test);

classDemoextendsComponent {
    render() {
        return (
            <div>
                xxxxx
                <FormTest>
                    { form=> {
                        this.form= form;
                        return (
                            <Form><Form.Item>
                                    {getFieldDecorator('field', xxx)(
                                        <Input placeholder="请输入链接地址"/>
                                    )}
                                </Form.Item></Form>
                        )
                    }}
                </FormTest></div>
        )
    }
}
复制代码
#第九道菜粉丝白菜虾仁汤第九道菜:粉丝白菜虾仁汤

子组件改变父组件的state方式有很多种,可以在父组件设置一个通用函数,类似:setParentState,通过子组件回调处理时,就可以更方便的统一处理:

// 父组件
state = {
    data: {}
}
setParentState=obj=> {
    this.setState(obj);
}
// 子组件onClick= () => {
    this.props.setParentState({ data: xxx });
}
复制代码
#第十道菜麻婆豆腐第十道菜:麻婆豆腐

永远不要直接设置state的值:this.state.data = { a: 1 }。这个会导致几个问题: 1:组件不会重新渲染 2:shouldComponentUpdate(nextProps, nextState) 函数里面 this.state的值是已经改变了,和nextState的值相同。

举个栗子:

// wrong
const { data } = this.state;
data.a = 1;     // 等价于this.state.data.a = 1;
this.setState({ data }); // shouldComponentUpdate里面观察到 this.state 和nextState的值是相同的
// 此时函数里面性能相关的优化是无效的

// correct  需要用到当前state值的写法
this.setState(state => ({ data: {...state.data, a: 1} }))
复制代码

各位客官,菜已上齐,请慢用

react相关讨论,请加Q群:743490497

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值