react 合并数组_React 常被忽视的细节。

react 合并数组_React 常被忽视的细节。_第1张图片

一. 数组循环时的key值

为了帮 React 实现 数组的最优调和(reconciliation)时,我们需要为循环的组件加上 key,不然React 会提示 :

3f2cae8a73a91e9d50887e6018ce8b32.png

然后为了图方便,很多人就会直接将 Array.map(item, index) 中的 index 当作 key 值:

const Arr = [
  {
       name:'Larry'}, 
  {
       name:'Lucy'}
];

Arr.map((item, index)=>(
  
{ item}
))

虽然React不报错了,但是这样是错误的

必须保证 Arr 无论怎么变,从2个增加到5个或者n个,key都是唯一且不会变化。

二. React组件unmounted之后setState的报错处理

我们常在 componentDidMount 里面(最好别在其他生命周期中执行ajax) 进行 ajax 请求,然后在回调函数中 通过 setState 来render视图,这是无可厚非的。但是偶尔会报错:

74e06180de3c375210c86b4b12d4126c.png

这是因为在组件卸载后执行了setState。

state = {
       name : 'Lucy' }
let time;
componentDidMount(){
      
  time = setTimeout(()=>{
      
    this.setState({
       name:'Larry' })
  },5000)
}

这段代码表示在组件加载完成后的5s后,执行 this.setState({ name:'Larry' }) ,但是如果在这5s内,你切换到其他组件或者页面(不包含该组件),该组件不存在了,就会报上面的错。

解决方法就是在 componentWillUnMount 中释放掉计时器。

componentWillUnMount(){
      
  clearTimeout(time)
}

鉴于大家经常使用fetch,在 componentWillUnMount cancel掉fetch的then就行了。

三. 子组件属性使用内嵌对象 或者 匿名函数

有些同学为了优化性能,构建组件时使用了shouldComponentUpdate 或者 PureComponent,就以为大功告成了,只要父级传来的props不变,子组件就不会被二次render了,其实不然。。。

class Child extends React.PureComponent{
      
  render(){
      
    ...
  }
}

class Parent extends React.PureComponent{
      
  render(){
      
    return(
      console.log(11) } style={
      {
       color:'#ccc' }}/>
    )
  }
}

上面代码中,onClick 和 style 是匿名函数和内嵌样式,每次父组件执行render,都会重新为这两个分配内存,子组件就会被重新渲染,两次render后的内存地址不相同,shouldComponentUpdate 和 PureComponent 就起不了作用。

把父组件改为下面就行:

const style = { color:'#ccc' }

class Parent extends React.PureComponent{

  onClick = () => {
    console.log(11)
  }

  render(){
    return(
      
    )
  }

}

这样,父组件执行 render 就不会再重新生成 onClick 和 style 对应的函数和值了。

四. fetch的HTTP状态码

fetch作为现在被广泛使用的网络访问方式,promise的链式调用方法解决了困扰前端工程师很长一段时间的回调地狱。然而,这个特性有一点不足,就是无论 http 状态码返回 404 或者 500,链式中的then一样会被调用,不会直接被catch捕获。

所以我们需要在第一次then中就判断 状态码是否 === 200 ?返回新的Promise : 抛出异常;

fetch(url)
 .then((res)=>{
      

   if(res.status !== 200){
      
     throw new Error ('请求失败')
   }

   res.json().then((res)=>{
      
      //继续后面的操作
   }).catch(err=>{
      
     console.log(err)
   })

  }).catch(err=>{
      
     console.log(err)
  })

五.在专用组件中渲染列表

这点在渲染大型数据集合时尤为重要。 React 在渲染大型数据集合时表现非常糟糕,因为协调器必须评估每个集合变化的集合所产生的组件。 因此,建议使用专门的组件来映射集合并渲染这个组件,且不再渲染其他组件:

bad:

class MyComponent extends Component {
      
    render() {
      
        const {
      todos, user} = this.props;
        return (
{ user.name}
    { todos.map(todo => )}
) } }

在上来的示例中,当 user.name 改变时,React 会不必要地协调所有的 TodoView 组件。尽管TodoView 组件不会重新渲染,但是协调的过程本身是非常昂贵的。

good:

class MyComponent extends Component {
      
    render() {
      
        const {
      todos, user} = this.props;
        return (
{ user.name}
) } } class TodosView extends Component { render() { const { todos} = this.props; return
    { todos.map(todo => )}
) } }

六. 子组件避免render

有些时候,我们在父组件中使用子组件,希望通过属性传递,让子组件自身控制显示还是隐藏,可以通过 return null 来避免render。

const Child = ({ show }) => {

  if (!show) {
    return null;
  }

  return (
    
child component
); } class Parent extends React.Component{ state = { show:true } toggle = () => { this.setState({ show: !this.state.show }) } render(){ return(
) } }

七. setState是异步的

在一次的函数运行中,setState不会立即执行,而是会等函数执行完成后,对多次state的操作进行合并(相同的state属性后者覆盖前者,不用的属性合并),然后进行一次setState。

class Demo extends React.Component{
      
  state = {
      
    number:1
  }

  add = () => {
      
    
    this.setState({
      
      number:this.state.number++
    })
    console.log(this.state.number)//输出1,没有变,说明setState是异步的,因为没有立即执行
    
    //再执行一次
    this.setState({
      
      number:this.state.number++
    })
    console.log(this.state.number)//还是输出1
  }

  print = () => console.log(this.state.number)

 
}

add();//执行add方法,调用了两次setState
print();//输出2,说明只对number进行了一次++

这样设计的原因:
1.合并更新,减少Dom渲染,降低页面性能。
2.即使每次执行setState都进行渲染,用户也看不到中间效果,只能看见最终的state渲染的页面

未完待续。。。

你可能感兴趣的:(react,合并数组)