React基础(一)

547 阅读7分钟

本文概述

  1. React.js概述
  2. React环境安装
  3. JSX
  4. render
  5. 事件监听
  6. state
  7. props
  8. 组件间通信

React.js概述

React.js是一个构建页面UI的库。
一个组件的显示形态和行为有可能是由某些数据决定的。而数据也可能发生改变的。
React.js提供一种非常高效的方式帮助我们做到数据和组件显示形态之间的同步。
React.js 只是个UI库,提供UI层面的解决方案,在实际项目中,需要借助其他库解决更复杂的问题,比如路由库React-Router,状态管理Redux等等。

React环境安装

直接使用React官方提供的脚手架工具。create-react-app。
安装步骤

//安装
npm install -g create-react-app
// 初始化项目
create-react-app hello-react
// 执行项目
cd hello-react
npm start

JSX

React基本代码

import React,{ Component } from 'react'
import ReactDOM from 'react-dom'
// React 依赖两个主要的库  
// React.js 负责 支持JSX语法
// ReactDOM 负责 渲染页面
class Header extends Component{
	render(){
  	return (
    	<div>hello world</div>
    )
  }
}
ReactDOM.render(
	<Header />,
  document.getElementById('root')
)

JSX原理

一个DOM元素包含的信息有:标签名,属性,子元素。
我们可以使用JavaScript对象来描述所有能用HTML表示的UI信息,但是用Javascript来写,结构太长了,而且不够直观。
为了解决整个问题,React扩展了JavaScript的语法,让JavaScript能够支持这种直接在js中编写类似HTML标签结构的语法。
在编译过程中,会将类似的HTML的JSX结构转换为JavaScript的对象结构。
JSX就是JavaScript对象。
JSX 通过Babel编译以及React构造 转化为JavaScript对象,再通过ReactDOM.render方法插入到页面中。
在React中,遇到大括号解析为JS,遇到<>解析为JSX语法。
即在JSX中,可以使用大括号插入一个表达式,表达式返回的结果会相应的渲染到页面上。

...
render () {
  const word = 'is good'
  return (
    <div>
      <h1>React 小书 {word}</h1>
    </div>
  )
}
...

{  } 中可以放置任何的JS代码,变量,表达式计算,函数执行等等。 

render

一个组件类必须实现render方法。
rende方法必须返回一个JSX元素,且只能返回一个。
返回并列多个JSX元素是不合法的,必须要用一个外层的JSX元素把所有内容包裹起来,也可以使用React本身提供的组件包裹。

事件监听

在react中实现事件监听是很容易的,只需要给需要监听的元素加上属性类似于" onClick"这样的属性。
注意: 
onClick 是大写的,必须使用驼峰法命名,后紧跟着的是一个表达式插入。
在React中不需要手动调用浏览器原生的addEventListener,React封装了一系列的 on* 属性,而且不需要考虑兼容性的问题,React已经封装好这些细节了。
这些事件监听的方法只能用在普通的HTML标签上,不能用在组件标签上。

event对象

和普通浏览器一样,事件监听函数也会被自动传入一个event对象,这个对象和普通的浏览器event对象所包含的属性和方法都是一致的,但是要注意的是,React中的event对象是React自己封装的,对外提供统一的方法和属性,并且不用考虑浏览器兼容的原因。

事件中的this

一般在某个类的实例方法中的this是指向这个实例本身。
但是在传递的时候,this可能会丢失。

...
  handleClickOnTitle (e) {
    console.log(this) // => null or undefined
  }
...

原因:
React在调用你所传给它的方法时,并不是通过对象方法的方式调用的,而是通过函数调用(直接调用),所以事件函数内并不能通过this获取实例。
解决方法:

  1. 需要手动绑定this指向,一般使用bind方法 在类的constructor方法内绑定。
  2. 以箭头函数的方式定义事件函数。(箭头函数中的this指向在定义时就已经决定了)

state和setState

一个组件的显示形态是可以由它数据状态和配置参数决定的。
一个组件可以拥有自己的状态。
在React中,state就是来存储这种状态的。

定义state

state是一个对象。
state在一个类的构造函数constructor中初始化。

...
class LikeButton extends Component {
  constructor () {
    super()
    this.state = { isLiked: false }
  }
}
...

修改state

修改组件的state只能使用setState方法。
setState方法有组件的Component父类提供。当调用这个方法,会更新组件的state,并且重新调用render方法,然后再把render方法所渲染的最新的内容显示到页面上。
setState方法接受一个对象或者函数作为参数。

setState方法接受对象作为参数

当传入一个对象的时候,该对象表示该组件的新状态,但是只需要传入需要更新的部分就可以了,不需要传入整个对象。

setState方法接受一个函数作为参数

使用setState,需要注意的点是,由于性能方面的考虑,通过setState方法修改组件的state并不会马上修改state,而是把这个对象放入一个更新队列里面,稍后才会从队列中把新的状态取出来再合并到state中,然后再触发组件更新。
但是,在某些场景中,又需要实时的拿到state去做一些处理。这个时候可以使用一个函数作为setState的参数。
该函数接受两个参数,一个是上个setState的结果,一个是最新的props
函数中接收的state和props都能保证为最新。
React会将最新的state和props传入这个函数,就可以使用该结果进行运算操作,然后返回一个新的对象作为更新state的对象。

 handleClickOnLikeButton () {
    this.setState((prevState) => {
      return { count: 0 }
    })
    this.setState((prevState) => {
      return { count: prevState.count + 1 } // 上一个 setState 的返回是 count 为 0,当前返回 1
    })
    this.setState((prevState) => {
      return { count: prevState.count + 2 } // 上一个 setState 的返回是 count 为 1,当前返回 3
    })
    // 最后的结果是 this.state.count 为 3
  }

props

组件是相互独立的,可复用的单元,一个组件可能在不同地方被用到,但是不同场景对同一个组件的要求可能不同。就需要组件有一定的配置性。
每个组件都有一个prop参数,它是一个对象,包含了对组件的配置。

使用props

组件内部通过 this.prop获取到组件的参数。
this.props.属性名

传入props

在使用一个组件的时候,可以把参数放在标签的属性当中,所有的属性都会作为props对象的键值。

// 使用props
class LikeButton extends Component {
 ...
  render () {
    const likedText = this.props.likedText || '取消'
    const unlikedText = this.props.unlikedText || '点赞'
    return (
      <button onClick={this.handleClickOnLikeButton.bind(this)}>
        {this.state.isLiked ? likedText : unlikedText} 👍
      </button>
    )
  }
}
//传入props
class Index extends Component {
  render () {
    return (
      <div>
        <LikeButton likedText='已赞' unlikedText='赞' />
      </div>
    )
  }
}

可以将任何类型的数据作为组件的参数,包括字符串,数字,对象,数组甚至于函数。

将函数作为参数传入组件

class Index extends Component{
	render(){
  	return (
    	<div>
      	<LikeButton 
      	 wordings={{likedText: '已赞', unlikedText: '赞'}}
         onClick={() => console.log('Click on like button!')}
        />	
/*
onClick={() => console.log('Click on like button!')}
onClick是属性名 
属性值是一个函数  ()=>{ console.log(...)}
传递给组件一个函数
*/
      </div>
    )
  }
}
class LikeButton extends Component {
  constructor () {
    super()
    this.state = { isLiked: false }
  }

  handleClickOnLikeButton () {
    this.setState({
      isLiked: !this.state.isLiked
    })
    if(this.props.onClick){
    	this.props.onClick()
      
    } 
  }

  render () {
    const wordings = this.props.wordings || {
      likedText: '取消',
      unlikedText: '点赞'
    }
    return (
      <button onClick={this.handleClickOnLikeButton.bind(this)}>
        {this.state.isLiked ? wordings.likedText : wordings.unlikedText} 👍
      </button>
    )
  }
}

可以通过this.props.onClick获取这个传进去的函数。

每次点击按钮的时候,控制台都会显示 Click on like button! 但是这个行为不是组件自己实现的,而是我们传进去的(相当于 自己实现了一个onClick函数)。

默认配置defaultProps

React提供了定义组件默认配置的方式

class...{
	static defaultProps = {
		likedText: '取消',
    unlikedText: '点赞'
	}
	render () {
    	return (
      		<button onClick={this.handleClickOnLikeButton.bind(this)}>
        	{this.state.isLiked
          	? this.props.likedText
          	: this.props.unlikedText} 👍
      	</button>
    	)
  }		
}

使用的时候不需要担心 在使用组件的时候没有传这个配置项,如果没有传进来,会使用默认配置项。

Props不可变

props一旦传进来,就不能改变。