当前位置: 首页 > news >正文

React基础知识(事件处理、受控组件与非受控组件、高阶函数、组件的生命周期)(三)

系列文章目录

第一章:React基础知识(React基本使用、JSX语法、React模块化与组件化)(一)
第二章:React基础知识(组件实例三大核心属性state、props、refs)(二)
第三章:React基础知识(事件处理、受控组件与非受控组件、高阶函数、组件的生命周期)(三)


文章目录

  • 系列文章目录
    • 一、事件处理
    • 二、收集表单数据
      • 2.1 非受控组件
      • 2.2 受控组件
    • 三、高阶函数
      • 3.1 函数柯里化
      • 3.2 不使用函数柯里化
    • 四、组件的生命周期
      • 4.1 react生命周期(17以前的旧版本)
      • 4.2 react生命周期(17以后的新版本,主要看这个)
        • 4.2.1. 即将废弃的勾子


为了简化代码,以下代码片段,除了有新的库需要引入会特意说明,其他引入react相关库的操作不再重复说明

一、事件处理

  • 通过onXxx属性指定事件处理函数(注意大小写)
    • React使用的是自定义(合成)事件, 而不是使用的原生DOM————为了更好的兼容性
    • React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————为了的高效
  • 可以通过event.target得到发生事件的DOM元素对象(触发事件的对象就是你当前需要获取的对象) ————不要过度使用ref

代码片段:

<body>
  <!-- 准备好一个“容器” -->
  <div id="test"></div>

  <!-- 引入react核心库 -->
  <script type="text/javascript" src="../js/react.development.js"></script>
  <!-- 引入react-dom,用于支持react操作DOM -->
  <script type="text/javascript" src="../js/react-dom.development.js"></script>
  <!-- 引入babel,用于将jsx转为js -->
  <script type="text/javascript" src="../js/babel.min.js"></script>

  <script type="text/babel">
    class Demo extends React.Component {
      myRef = React.createRef();
      myRef2 = React.createRef()
      showData = () => {
        // console.log(this.myRef)
        alert(this.myRef.current.value)

      }
      showData2 = (event) => {
        alert(event.target.value)
      }
      render() {
        return (
          <div>

            <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
            <button ref='btn' onClick={this.showData}>点我提示左侧数据</button>
            <input type="text" placeholder="失去焦点提示数据" onBlur={this.showData2} />
          </div>
        )
      }
    }
    ReactDOM.render(<Demo />, document.getElementById('test'));

  </script>
</body>

</html>

运行结果:
在这里插入图片描述

二、收集表单数据

2.1 非受控组件

要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以使用 ref 来从 DOM 节点中获取表单数据。在非受控组件中,你经常希望 React 能赋予组件一个初始值, 但是不去控制后续的更新。 在这种情况下,你可以指定一个 defaultValue 属性,而不是value。
简单的话说就是:仅仅获取用户输入得值,不绑定给state,现用现取
代码片段:

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	<!-- 引入react核心库,代码看上方 -->
	<script type="text/babel">
		//创建组件
		class Login extends React.Component{
			handleSubmit = (event)=>{
				event.preventDefault() //阻止表单提交
				const {username,password} = this
				alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`)
			}
			render(){
				return(
					<form onSubmit={this.handleSubmit}>
						用户名:<input ref={c => this.username = c} type="text" name="username"/>
						密码:<input ref={c => this.password = c} type="password" name="password"/>
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login/>,document.getElementById('test'))
	</script>
</body>
</html>

运行结果:
在这里插入图片描述

2.2 受控组件

在 HTML 中,表单元素(如 <input><textarea><select> )通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
简单的话说就是:保存或者修改操作,绑定给state
代码片段:

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库,代码看上方 -->

	<script type="text/babel">
		//创建组件
		class Login extends React.Component{

			//初始化状态
			state = {
				username:'', //用户名
				password:'' //密码
			}

			//保存用户名到状态中
			saveUsername = (event)=>{
				this.setState({username:event.target.value})
			}

			//保存密码到状态中
			savePassword = (event)=>{
				this.setState({password:event.target.value})
			}

			//表单提交的回调
			handleSubmit = (event)=>{
				event.preventDefault() //阻止表单提交
				const {username,password} = this.state
				alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
			}

			render(){
				return(
					<form onSubmit={this.handleSubmit}>
						用户名:<input onChange={this.saveUsername} type="text" name="username"/>
						密码:<input onChange={this.savePassword} type="password" name="password"/>
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login/>,document.getElementById('test'))
	</script>
</body>
</html>

运行结果:
在这里插入图片描述

三、高阶函数

高阶函数: 如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。

  • 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。

  • 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。

  • 常见的高阶函数有: Promise、setTimeout、arr.map()等等

函数的柯里化: 通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

function sum(a){
		return(b)=>{
			return (c)=>{
				return a+b+c
					}
				}
			}

3.1 函数柯里化

代码片段:

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->

	<script type="text/babel">
		//创建组件
		class Login extends React.Component{
			//初始化状态
			state = {
				username:'', //用户名
				password:'' //密码
			}

			//保存表单数据到状态中
			saveFormData = (dataType)=>{
				return (event)=>{
					this.setState({[dataType]:event.target.value})
				}
			}

			//表单提交的回调
			handleSubmit = (event)=>{
				event.preventDefault() //阻止表单提交
				const {username,password} = this.state
				alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
			}
			render(){
				return(
					<form onSubmit={this.handleSubmit}>
					//如果传递参数,此处会直接调用函数,onChange会被赋值成当前函数的返回值
						用户名:<input onChange={this.saveFormData('username')} type="text" name="username"/>
						密码:<input onChange={this.saveFormData('password')} type="password" name="password"/>
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login/>,document.getElementById('test'))
	</script>
</body>
</html>

运行结果:
在这里插入图片描述

3.2 不使用函数柯里化

代码片段:

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->

	<script type="text/babel">
		//创建组件
		class Login extends React.Component{
			//初始化状态
			state = {
				username:'', //用户名
				password:'' //密码
			}

			//保存表单数据到状态中
			saveFormData = (dataType,event)=>{
				this.setState({[dataType]:event.target.value})
			}

			//表单提交的回调
			handleSubmit = (event)=>{
				event.preventDefault() //阻止表单提交
				const {username,password} = this.state
				alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
			}
			render(){
				return(
					<form onSubmit={this.handleSubmit}>
					//使用箭头函数
						用户名:<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/>
						密码:<input onChange={event => this.saveFormData('password',event) } type="password" name="password"/>
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login/>,document.getElementById('test'))
	</script>
</body>
</html>

运行结果:

在这里插入图片描述

四、组件的生命周期

1.组件从创建到死亡它会经历一些特定的阶段。
2.React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用
3.我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

4.1 react生命周期(17以前的旧版本)

在这里插入图片描述

1. 初始化阶段: 由ReactDOM.render()触发---初次渲染

  • constructor()

  • componentWillMount()

  • render()

  • componentDidMount() =====> 常用,一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发

  • shouldComponentUpdate()
  • componentWillUpdate()
  • render() =====> 必须使用的一个
  • componentDidUpdate()

3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发

  • componentWillUnmount() =====> 常用
    一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

代码片段:

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	<div id="test1"></div>
	<!-- 引入react核心库 -->

	<script type="text/babel">
		//创建组件
		class Count extends React.Component {

			//构造器
			constructor(props) {
				console.log('Count---constructor');
				super(props)
				//初始化状态
				this.state = { count: 0 }
			}

			//加1按钮的回调
			add = () => {
				//获取原状态
				const { count } = this.state
				//更新状态
				this.setState({ count: count + 1 })
			}

			//卸载组件按钮的回调
			death = () => {
				ReactDOM.unmountComponentAtNode(document.getElementById('test'))
			}

			//强制更新按钮的回调
			force = () => {
				this.forceUpdate()
			}

			//组件将要挂载的钩子
			componentWillMount () {
				console.log('Count---componentWillMount');
			}

			//组件挂载完毕的钩子
			componentDidMount () {
				console.log('Count---componentDidMount');
			}

			//组件将要卸载的钩子
			componentWillUnmount () {
				console.log('Count---componentWillUnmount');
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate () {
				console.log('Count---shouldComponentUpdate');
				return true
			}

			//组件将要更新的钩子
			componentWillUpdate () {
				console.log('Count---componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate () {
				console.log('Count---componentDidUpdate');
			}

			render () {
				console.log('Count---render');
				const { count } = this.state
				return (
					<div>
						<h2>当前求和为:{count}</h2>
						<button onClick={this.add}>点我+1</button>
						<button onClick={this.death}>卸载组件</button>
						<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
						<hr />
					</div>
				)
			}
		}

		//父组件A
		class A extends React.Component {
			//初始化状态
			state = { carName: '奔驰' }

			changeCar = () => {
				this.setState({ carName: '奥拓' })
			}
			//组件将要挂载的钩子
			componentWillMount () {
				console.log('A---componentWillMount');
			}

			//组件挂载完毕的钩子
			componentDidMount () {
				console.log('A---componentDidMount');
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate () {
				console.log('A---shouldComponentUpdate');
				return true
			}

			//组件将要更新的钩子
			componentWillUpdate () {
				console.log('A---componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate () {
				console.log('A---componentDidUpdate');
			}

			render () {
				console.log('A---render');

				return (
					<div>
						<div>我是A组件</div>
						<button onClick={this.changeCar}>换车</button>
						{	/*组件嵌套,调用子组件内容*/}
						<B carName={this.state.carName} />
					</div>
				)
			}
		}

		//子组件B
		class B extends React.Component {
			//组件将要挂载的钩子
			componentWillMount () {
				console.log('B---componentWillMount');
			}

			//组件挂载完毕的钩子
			componentDidMount () {
				console.log('B---componentDidMount');
			}

			//组件将要接收新的props的钩子
			componentWillReceiveProps (props) {
				console.log('B---componentWillReceiveProps', props);
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate () {
				console.log('B---shouldComponentUpdate');
				return true
			}
			//组件将要更新的钩子
			componentWillUpdate () {
				console.log('B---componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate () {
				console.log('B---componentDidUpdate');
			}

			render () {
				console.log('B---render');
				return (
					<div>我是B组件,接收到的车是:{this.props.carName}</div>
				)
			}
		}

		//渲染组件
		ReactDOM.render(<Count />, document.getElementById('test'))
		ReactDOM.render(<A />, document.getElementById('test1'))

	</script>
</body>

</html>

运行结果:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4.2 react生命周期(17以后的新版本,主要看这个)

在这里插入图片描述1. 初始化阶段: 由ReactDOM.render()触发---初次渲染

  • constructor()

    在 React 组件挂载之前,会调用它的构造函数。主要用于初始化state、为实例方法绑定this。如果组件类继承自React.Component,在构造函数中应先调用super(props),需要注意的是,不用在构造函数中使用this.setState()。还可以更改事件处理程序this的指向。

  • static getDerivedStateFromProps(props, state)

    响应 Props 变化之后进行更新的方式。这个生命周期的功能实际上就是将传入的props映射到state上面。 该方法是一个静态方法,无法通过this直接访问。这个函数会在每次re-rendering之前被调用。该方法的返回值会修改state,如果不想修改state,则直接返回null

  • render()

    该方法是 class 组件中唯一必须实现的方法。render函数应该是一个纯函数,意味着在不修改state值的时候该函数的返回值是一样的。

  • componentDidMount() =====> 常用

    会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在componentWillUnmount() 里取消订阅 。

2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发

  • static getDerivedStateFromProps(nextProps, nextState)
  • shouldComponentUpdate(nextProps, nextState)

根据该方法返回值,返回值默认为true判断 React 组件的输出是否受当前 state 或 props 更改的影响,返回值默认为true。默认行为是 state 每次发生变化组件都会重新渲染。大部分情况下,你应该遵循默认行为

  • render()

  • getSnapshotBeforeUpdate(prevProps, prevState)

    该钩子会在dom和refs渲染之前调用,返回的值可以传递给componentDidUpdate

  • componentDidUpdate(prevProps, prevState, snapshot)

    会在更新后会被立即调用,首次渲染不会执行此方法。当组件更新后,可以在此处对DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。你也可以在componentDidUpdate() 中直接调用 setState() ,但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额 外的重新渲染,虽然用户不可⻅,但会影响组件性能。不要将 props “镜像”给 state,请考虑直接使用 props。

3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发

  • componentWillUnmount() 当组件阶段当组件从 DOM 中移除时

代码片段:

<body>
  <!-- 准备好一个“容器” -->
  <div id="test"></div>

  <!-- 引入react核心库 -->
  <script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
  <!-- 引入react-dom,用于支持react操作DOM -->
  <script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
  <!-- 引入babel,用于将jsx转为js -->
  <script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

  <script type="text/babel">
    //创建组件
    class Count extends React.Component {
      //构造器
      constructor(props) {
        console.log('Count---constructor');
        super(props)
        //初始化状态
        this.state = { count: 0 }
      }

      //加1按钮的回调
      add = () => {
        //获取原状态
        const { count } = this.state
        //更新状态
        this.setState({ count: count + 1 })
      }

      //卸载组件按钮的回调
      death = () => {
        ReactDOM.unmountComponentAtNode(document.getElementById('test'))
      }

      //强制更新按钮的回调
      force = () => {
        this.forceUpdate()
      }

      //若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps
      static getDerivedStateFromProps(props, state) {
        console.log('getDerivedStateFromProps', props, state);
        //return {...props}
        return null
      }

      //在更新之前获取快照
      getSnapshotBeforeUpdate() {
        console.log('getSnapshotBeforeUpdate');
        return 'atguigu'
      }

      //组件挂载完毕的钩子
      componentDidMount() {
        console.log('Count---componentDidMount');
      }

      //组件将要卸载的钩子
      componentWillUnmount() {
        console.log('Count---componentWillUnmount');
      }

      //控制组件更新的“阀门”
      shouldComponentUpdate() {
        console.log('Count---shouldComponentUpdate');
        return true
      }

      //组件更新完毕的钩子
      componentDidUpdate(preProps, preState, snapshotValue) {
        console.log('Count---componentDidUpdate', preProps, preState, snapshotValue);
      }

      render() {
        console.log('Count---render');
        const { count } = this.state
        return (
          <div>
            <h2>当前求和为:{count}</h2>
            <button onClick={this.add}>点我+1</button>
            <button onClick={this.death}>卸载组件</button>
            <button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
          </div>
        )
      }
    }

    //渲染组件
    ReactDOM.render(<Count count={199} />, document.getElementById('test'))
  </script>
</body>

</html>

运行结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.2.1. 即将废弃的勾子

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。

相关文章:

  • 多姿wordpress/产品营销方案
  • wordpress 视频列表/免费制作网站app
  • 关于做ppt的网站有哪些内容/seo排名哪家正规
  • 上海网站高端定制/百度如何做推广
  • 建设中的网站备案期间做什/武汉网站排名推广
  • ps个人网站制作流程/百度推广登录后台登录入口
  • 制作嵌入式根文件系统
  • js获取某一时间到现在的总时间以及svg图标统一管理方法的封装
  • 编程艺术之变成原则
  • 高品质蓝牙耳机排行榜,值得入手的四款蓝牙耳机分享
  • 车载以太网 - 初识DoIP - 01
  • Java -- OSS对象存储服务(Object Storage Service,简称 OSS)文件服务器
  • 【云原生 | 48】Etcd集群管理
  • “0基础、学历无优势、逻辑能力一般……”能转行做程序员吗?
  • 【C++】多态(万字详解) —— 条件 | 虚函数重写 | 抽象类 | 多态的原理
  • Vue:从组件开始学习
  • Python find()、rfind()方法
  • Android -- 每日一问:如何实现自定义View?