React 的生命周期、组建通信及非受控组件(二)

一、前言及补充内容

        昨天学习了 初识、构建以及 React 事件的基本用法和一些注意点,我们大概也掌握了 React 框架的语法. 当然其中也落下了几个问题,我就统一放到这篇文章来处理了.

1. 项目的启动报错问题(三种解决方案)

        昨天在创建完项目之后,运行也是报了错误,困扰了很久,最终找到了这些方法,并且全部可行,希望对你们有所帮助

  1. 运行的项目路径不对 cd 到创建的项目路径,再运行

恩… 这个,不要小瞧这个错误,在你某些时候分心,忘了或者看别人自动化构建项目运行时,一味的执行命令,却忘了创建完项目,需要 cd 到指定项目文件夹.那样肯定会报错.这个问题,我昨天也碰到过了,第一次创建运行对于新手还是特别需要注意的

正确的步骤:
安装 React 框架 : npm i -g create-react-app
创建项目 : create-react-app 项目名称 (项目名称避免使用中文)
进入创建的项目路径 : cd 项目名字
运行项目 (如果这里运行出错,请看下面解决方案) : npm start

2. 缺少依赖

        我们创建完项目之后,会在 package.json 配置中的 script 中看到以下代码

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },

eact-scripts是create-react-app中的一个核心包一些脚本和工具的默认配置都集成在里面,执行命令 npm run eject 会复制所有依赖文件和相应的依赖(webpack、babel等)到你的项目。是个单向的操作,一旦 eject ,npm run eject的操作是不可逆的

正确的步骤 :
在你创建完项目之后,运行报错,就 输入复制依赖命令 : npm run eject
然后再运行项目 : npm run start

3. webpack 版本不同

        第三种方法,在昨天的博客中用到了这种方法,并下载了这张图,让你明白具体是怎么回事

为了解决这个 webpack 版本不同的问题,我们在 src 同级目录下创建 .env 文件夹,然后放入一下代码,就可以解决

SKIP_PREFLIGHT_CHECK=true

2. 无法获取 this 值

        在js中class的方法默认不会绑定this,必须使用this.handleClick并把他传入onClick,否则调用函数时this的值为undefined。解决绑定this的三种方法:

        1. 构造函数绑定this(推荐)

class Button extends React.Component {
 
constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
 
  handleClick(){
    console.log('this is:', this);
  }
 
  render() {
 
    return (
      <button onClick={this.handleClick}>点我</button>
    );
  }
}

        2. 调用的时候绑定this

class Button extends React.Component {
 
  handleClick(){
    console.log('this is:', this);
  }
 
  render() {
 
    return (
      <button onClick={this.handleClick.bind(this)}>点我</button>
    );
  }
}

        3. 箭头函数:箭头函数中的this只会固定的指向声明时的this指向

return (
      <button onClick={() => this.handleClick()}>点我</button>
    );

3. babel 配置

        我的 babel 配置是在一篇博客上学习的,这里就不在一 一介绍了,你们可以前去他的博客查看学习

网址 : babel 配置教学网址

二、React 父传子

  1. 父组件提供要传递的state数据
  2. 给子组件标签添加属性,值为state中的数据
  3. 子组件通过props接收父组件中传递的数据

        代码实例 :

// 父组件
class Parent extends React.Component{
  state={
    lastName:"张三"
  }

  render(){
    return (
      <div className="parent">
        父组件:<Child name={this.state.lastName}/>
      </div>
    )
  }
}

// 子组件
const Child = (props)=>{
  console.log(props)
  return (
    <div className="child">
      <p>子组件,接收到父组件的数据: {props.name}</p>
    </div>
  )
}

        运行后查看浏览器 :
在这里插入图片描述

三、React 子传父

  1. 父组件提供一个回调函数(用于接收数据)
  2. 将该函数作为属性的值,传递给子组件
  3. 子组件通过 props 调用回调函数
  4. 将子组件的数据作为参数传递给回调函数

        代码实例 :

// 父组件
class Parent extends React.Component{

  state = {
    parentMsg:""
  }

  // 提供回调函数,用来接收数据
  getChildMsg = data =>{
    console.log("我收到了子组件中传递过来的数据 :" ,data)

    this.setState({
      parentMsg:data 
    })
  }
  render(){
    return (
      <div className="parent">
        父组件: {this.state.parentMsg}
        <Child getMsg={this.getChildMsg}/>
      </div>
    )
  }
}

// 子组件
class Child extends React.Component{
  state = {
    msg:"下大雨了"
  }

  handleClick = () =>{
    // 子组件调用父组件中传递过来的回调函数
    this.props.getMsg(this.state.msg)
  }
  render(){  
    return (
      <div className="child">
        子组件: <button onClick={this.handleClick}>点我,给父组件传递数据</button>
      </div>
    )
  }
  
}

        运行后查看浏览器 :
在这里插入图片描述

四、组件通讯

        将共享状态提升到最近的公共父组件中,由公共组件管理这个状态

公共组件职责 : 1. 提供共享状态 2. 提供操作共享状态的方法
要通讯的子组件 : 只需通过 props 接收状态或操作状态的方法

        代码实例 :

// 父组件
class Counter extends React.Component{
  // 提供共享状态
  state = {
    count:0
  }

  // 提供修改状态的方法
  xiugai = () =>{
    this.setState({
      count:this.state.count + 1
    })
  }
  render(){
    return (
      <div>
        <Child count={this.state.count}/>
        <Child2 xiugai={this.xiugai}/>
      </div>
    )
  }
}

const Child = (props) =>{
  return <h1>计算器 : {props.count}</h1>
}

const Child2 = (props) =>{
  return <button onClick={()=>props.xiugai()}>+1</button>
}

        运行后查看浏览器 :
在这里插入图片描述

五、生命周期

1. 组件生命周期概述

        意义 : 组件的生命周期有助于理解组件的运行方式,完成更复杂的组件功能、分析组件错误原因等
        组件的生命周期 : 组件从被创建到挂载页面中运行,再到组件不用时卸载的过程
        生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数
        钩子函数的作用 : 为开发人员在不同阶段操作组件提供了时机

2. 生命周期的三个状态

Mounting:已插入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM

3. 挂载卸载过程

        constructor

constructor完成数据的初始化,接受2个参数:props和content,当想在函数内部使用这两个参数,就必须使用super()传入这两个参数
注意:只要使用constructor就必须写super,否则会导致this的指向错误

        componentWillMount

componentWillMount一般用的比较少,它更多的时在服务端渲染时使用,当前周期代表的时组件已经经历过constructor初始化数据后,但是还未渲染DOM的时候

        compontntDidMount

组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染

        componentWillUnmount

这个周期完成组件的卸载和数据的销毁
清除定时器
移除事件监听addEventListener

4. 更新过程

        componentWillReceiveProps(nextProps)

接收父组件改变后的props
接收一个参数nextProps
对比nextProps和this.props,将nextProps的state为当前组件的state,从而重新渲染

        shouldComponentUpdate(nextProps, nextState)

主要用于性能优化
可以控制组件的重新渲染的生命周期,因为在react中,setState后,state发生变化,组件重新渲染,这个周期可以return false来阻止组件的更新
父组件的重新渲染会导致其子组件的重新渲染,这个时候我们是不需要所有的子组件都重新渲染,所以在子组件的shouldComponentUpdate中做判断

        componentWillUpdate(nextProps, nextState)

shouldComponentUpdate返回true以后,组件进行重新渲染的过程,在这个周期同样可以拿到nexeProps和nextState

        componentDidUpdate(prevProps,prevState)

组件更新完毕后,react在componentDidMount之后,每次重新渲染都会进入这个生命周期,这里可以拿到prevProps和prevState,即更新前的props和state

        render

这个周期react会生成一份虚拟DOM树,每次组件更新时,react会通过diff算法比较新旧DOM树,找到最小差异的DOM节点,重新渲染

4. 生命周期图解

在这里插入图片描述

六、受控组件

<input
    type="text"
    value={this.state.value}
    onChange={(e) => {
        this.setState({
            value: e.target.value.toUpperCase(),
        });
    }}
/>

        受控组件要绑定一个change事件;每当表单的状态发生变化,都会被写入组件的state中,这种组件在React中被称为受控组件;在受控组件中,组件渲染出的状态与它的value或者checked prop向对应.react通过这种方式消除了组件的局部状态,是的应用的整个状态可控.

        React受控组件更新state的流程:

1.可以通过初始state中设置表单的默认值;
2.每当表单的值发生变化时,调用onChange事件处理器;
3.事件处理器通过合成事件对象e拿到改变后的状态,并更新应用的state.
4.setState触发视图的重新渲染,完成表单组件值得更新

react中数据是单向流动的.从示例中,我们能看出来表单的数据来源于组件的state,并通过props传入,这也称为单向数据绑定.然后,我们又通过onChange事件处理器将新的表单数据写回到state,完成了双向数据绑定.

七、非受控组件

import React, { Component } from 'react';

class UnControlled extends Component {
    handleSubmit = (e) => {
        console.log(e);
        e.preventDefault();
        console.log(this.name.value);
    }
    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <input type="text" ref={i => this.name = i} defaultValue="BeiJing" />
                <button type="submit">Submit</button>
            </form>
        );
    }
}

export default UnControlled;

如果一个表单组件没有value props(单选按钮和复选按钮对应的是 checked props)时,就可以称为非受控组件;

使用defaultValue和defaultChecked来表示组件的默认状态;
通过 defaultValue和defaultChecked来设置组件的默认值,它仅会被渲染一次,在后续的渲染时并不起作用

八、总结

        今日这篇博客补充解决了昨天落下的问题,也新学习了组件之间进行通讯、生命周期、受控组件以及非受控组件. 也学习到了新的编程思维语法.今天的学习到此结束,希望对你们有所帮助.我们下期见!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值