初识React

182 阅读6分钟

初识react

从vue到react,可以发现这两种框架有很大的相似之处

1.相同之处

有着相似的语法,相似的生命周期,相似的父子组件传值、子父组件传值和非父子组件传值。

2.不同之处着实太多,在此不一一说明

着重介绍react框架的重点和核心点。
关于react的组件传值
父子组件传值 ||从父组件到子组件不仅可以传数据,还可以传事件

//父组件
import React, { Component } from "react";
//引入子组件
import ChildModule from "./components/ChildModule";
export class FacherModule extends Component {
//定义数据
  state = {
    data: [
      {
        id: 1,
        name: "name1",
        age: 18,
        sex: 男,
      }
    ],
  };
  //事件
  dataOnClickFun = (e) => {
    console.log(e.target);
  };
  render() {
    return (
      <div>
        FacherModule
        <ChildModule value={this.props.data}  dataFun={this.dataOnClickFun}></ChildModule>
      </div>
    );
  }
}

export default FacherModule;

//子组件
import React, { Component } from "react";
import "../App.css";

export class ChildModule extends Component {
  constructor(props) {
    super(props);
    console.log(props);
  }
  render() {
    return (
      <div>
        ChildModule
        {this.props.value.map((value, index) => {
          return (
            <ul key={value.id} className="ulBox">
              <li>{value.id}</li>
              <li>{value.name}</li>
              <li>{value.age}</li>
            </ul>
          );
        })}
      </div>
    );
  }
}

export default ChildModule;

子组件输出结果

![UG`KS[T{E_}I%WXZ7FL1_A.png 是个object类型的数据,父子组件传值已基本完成,注意: value可以传数组,对象,字符串等数据类型

1.子组件到父组件传值

//父组件代码
import React, { Component } from "react";
//引入子组件
import ChildModule from "./components/ChildModule";
export class FatcherModule extends Component {
//从子组件触发的事件,
  changeFatherval = (value) => {
    console.log(value);
  };
  render() {
    return (
      <div>
        FatcherModule
        //toFatcher 在父组件中要与子组件传递的名要一致  
        <ChildModule toFatcher={this.changeFatherval}></ChildModule>
      </div>
    );
  }
}
export default FatcherModule;
//子组件
import React, { Component } from "react";
import "../App.css";
export class ChildModule extends Component {
  constructor(props) {
    super(props);
    console.log(props);
  }
  //子组件触发的事件
  ChildFun = () => {
    console.log("111");
    //toFatcher子组件传递的事件名称  
    this.props.toFatcher("从子组件传到父组件的数据");
  };
  render() {
    return (
      <div>
        ChildModule
        <button onClick={this.ChildFun}>子到父传值</button>
      </div>
    );
  }
}
export default ChildModule;

2.无论是vue还是React,都有关于请求数据,发送求情这以行为,在此以axiox请求举例说明
在src文件下建utils文件夹,内有request.js文件。

//引入axios
import axios from 'axios'
import qs from 'qs'
//get delete post put
// 使用由库提供的配置的默认值来创建实例
var requests = axios.create()
// 覆写库的超时默认值
requests.defaults.timeout = 50000
//设置请求头
requests.defaults.baseURL = ''
// 添加请求拦截器
requests.interceptors.request.use(
  function (config) {
    //设置token 1.0
    config.headers = {
      ...config.headers,
      token名: 'token值',
    }
    //2.0
     if (config.data && !(config.data instanceof FormData)) {
      config.data = qs.stringify(config.data)
    }
     config.url && (config.url =`${config.url}token=1ec949a15fb709370f`)
    // let tokenStr = localStorage.getItem('token')
    return config
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error)
  }
)

// 添加响应拦截器
requests.interceptors.response.use(
  function (response) {
  //请求到的数据进行脱壳处理
  const {data}=response
    return data
  },
  function (error) {
    return Promise.reject(error)
  }
)
//get请求方式
const get = (url, data) => {
  return new Promise((res, rej) => {
    requests
      .get(url, { params: data })
      .then(val => {
        res(val)
      })
      .catch(err => {
        rej(err)
      })
  })
}
//deleter请求方式
const deleter = (url, data) => {
  return new Promise((res, rej) => {
    requests
      .delete(url, { params: data })
      .then(val => {
        res(val)
      })
      .catch(err => {
        rej(err)
      })
  })
}
//post请求方式
const post = (url, data) => {
  return new Promise((res, rej) => {
    requests
      .post(url, data)
      .then(val => {
        res(val)
      })
      .catch(err => {
        rej(err)
      })
  })
}
//put请求方式
const put = (url, data) => {
  return new Promise((res, rej) => {
    requests
      .put(url, data)
      .then(success => {
        res(success)
      })
      .catch(error => {
        rej(error)
      })
  })
}
export { get, post, deleter,put }

注:请求封装和发送请求需要传递的token值的方式和请求到的数据进行脱壳处理,请求失败处理已经进行了分情况操作
引入:

//引入
import {post,get,put,deleter} from "./utils/request"

在生命周期里调用

//发送请求
//挂载之后
componentDidMount(){
post("接口地址").then(res=>{console.log(res)}).catch(err=>{console.log(err)})
  }//可以获取到数据

3.既然涉及到了React的生命周期,接下来会分析各个生命周期 react有三个生命周期阶段

1.挂载过程

1.1 constructor()
constructor() 中完成了React数据的初始化,它接受两个参数:props和context,当想在函数内部使用这两个参数时,需使用super()传入这两个参数。
注意:只要使用了constructor()就必须写super(),否则会导致this指向错误。
1.2 componentWillMount()
componentWillMount()一般用的比较少,它更多的是在服务端渲染时使用。它代表的过程是组件已经经历了constructor()初始化数据后,但是还未渲染DOM时。
1.3 componentDidMount()
组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据使用setState进行数据修改之后组件会重新渲染

2.卸载过程

2.1.componentWillUnmount () 在此处完成组件的卸载和数据的销毁。
1.1 clear你在组建中所有的setTimeout,setInterval
1.2 移除所有组建中的监听 removeEventListener
1.3 有时候会碰到这个warning:

Can only update a mounted or mounting component. This usually      means you called setState() on an unmounted component. This is a   no-op. Please check the code for the undefined component.

解析:因为你在组件中的ajax请求返回setState,而你组件销毁的时候,请求还未完成,因此会报warning
解决方法:

componentDidMount() {
    this.isMount === true
   get().then(res => {
    this.isMount && this.setState({   // 增加条件ismount为true时 当&&前面的条件为真时执行后面的操作
      data:res
    })
})
}
componentWillUnmount() {
    this.isMount === false
}

3.更新过程

3.1 componentWillReceiveProps (nextProps)

  1. 在接受父组件改变后的props需要重新渲染组件时用到的比较多
  2. 接受一个参数nextProps
  3. 通过对比nextProps和this.props,将nextProps的state为当前组件的state,从而重新渲染组件
componentWillReceiveProps (nextProps) {
    nextProps.openNotice !== this.props.openNotice&&this.setState({
        openNotice:nextProps.openNotice
    },() => {
      console.log(this.state.openNotice:nextProps)
      //将state更新为nextProps,在setState的第二个参数(回调)可以打         印出新的state
  })
}

3.2 shouldComponentUpdate(nextProps,nextState)

  1. 主要用于性能优化(部分更新)
  2. 唯一用于控制组件重新渲染的生命周期,由于在react中,setState以后,state发生变化,组件会进入重新渲染的流程,在这里return false可以阻止组件的更新
  3. 因为react父组件的重新渲染会导致其所有子组件的重新渲染,这个时候其实我们是不需要所有子组件都跟着重新渲染的,因此需要在子组件的该生命周期中做判断
    3.3 componentWillUpdate (nextProps,nextState)
    shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate,这里同样可以拿到nextProps和nextState。
    3.4 componentDidUpdate(prevProps,prevState)
    组件更新完毕后,react只会在第一次初始化成功会进入componentDidmount,之后每次重新渲染后都会进入这个生命周期,这里可以拿到prevProps和prevState,即更新前的props和state。
    3.5 render()
    render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。

4. 新增的生命周期

4.1 getDerivedStateFromProps(nextProps, prevState)
代替componentWillReceiveProps()。老版本中的componentWillReceiveProps()方法判断前后两个 props 是否相同,如果不同再将新的 props 更新到相应的 state 上去。这样做一来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。
4.2 getSnapshotBeforeUpdate(prevProps, prevState)
代替componentWillUpdate。 常见的 componentWillUpdate 的用例是在组件更新前,读取当前某个 DOM 元素的状态,并在 componentDidUpdate 中进行相应的处理。 这两者的区别在于:
4.2.1. 在 React 开启异步渲染模式后,在 render 阶段读取到的 DOM 元素状态并不总是和 commit 阶段相同,这就导致在 componentDidUpdate 中使用 componentWillUpdate 中读取到的 DOM 元素状态是不安全的,因为这时的值很有可能已经失效了。
4.2.2. getSnapshotBeforeUpdate 会在最终的 render 之前被调用,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态是可以保证与 componentDidUpdate 中一致的。 此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。