React入门与基础

289 阅读5分钟

REACT脚手架:create-react-app

  • 全局环境安装脚手架 $ npm install -g create-react-app

  • 基于脚手架快速构建工程化的项目 $ create-react-app xxx (如果电脑上安装了yarn,默认基于yarn安装)

  • 不想安装在全局,可以基于npx一步到位 $ npx create-react-app xxx

脚手架创建的项目目录

  • node_models 所有安装的模块
  • public
    • index.html SPA单页面应用中,各组件最后合并渲染完成的结果都会放入到页面的#root盒子中呈现
    • xxx.html MPA/SPA这里存放的是最后编译页面的模板
    • 我们还可能会在此放一些公共资源,把这些资源直接基于SRC/LINK的方式调入到页面模板中,而不是基于webpack最后合并在一起 (不建议:但是项目中,可能存在一些模块不支持CommonJS/ES6Module规范,此时我们只能在这里直接引入使用了)
  • src 整个项目的大部分源码都写在这个目录下
    • index.js 项目的入口,webpack从这个文件开始导入打包 (MPA中需要创建多入口文件)
    • api 数据处理
    • store REDUX公共状态管理
    • asset 存储公共资源的
    • utils 公共的JS模块
    • routes 路由管理的
    • components 公共的组件
    • ...
  • package.json

默认的配置清单

  • 生产依赖项
    • react BEACT框架的核心,提供了状态、属性、组件、生命周期等
    • react-dom 把JSX语法渲染成为真实的DOM,最后显示在浏览器中
    • react-scripts 包含了当前工程化项目中webpack配置的东西 (嫌弃把webpack放到项目目录中看上去太丑,脚手架把所有的配置项和依赖都隐藏到node_modules中了,react-scripts这个REACT脚本执行命令,会通知webpack打包编译)
  • scripts 当前项目课执行的脚本命令 ($ yarn xxx)
    • $ yarn start =>开发环境下启动项目 (会默认基于WEBPACK-DEV-SERVER创建一个服务,用来随时编译和渲染开发的内容)
    • $ yarn build => 生产环境下,把编写的内容打包编译,放到build文件目录下 (服务器部署)
    • $ yarn eject => 把所有隐藏在node_modules中的webpack配置项都暴露出来 (方便自己根据项目需求,二次更改webpack配置)

REACT中的组件

在react工程化项目中 (vscode),我们会把需要写react组件的JS命名为.jsx,这样只有一个目的,让创建的文件识别JSX语法,而在create-react-app脚手架创建的项目中,已经包含了对.jsx文件的处理 每一个组件都是一个单独的个体 (数据私有、有自己完整的生命周期、有自己的视图...) 只要在JS中使用JSX,则必须要引入REACT (因为需要用到CREATE-ELEMENT)

函数式组件 只要让函数返回一个JSX元素即可 (掌握:props)

+ 特点:简单(开发简单和渲染也快),但是一旦组件 被调用,里面的内容渲染完成,当前组件中的信息基本上就不变了 (除非:重新被调用组件传递不同的属性信息) =>”静态组件“:没有state状态管控内容的随时变化,也没有生命周期函数等
  1. 基于React.Component类创建组件
  2. REACT HOOK
  • Props:在ReactDOM.render进行处理的时候,如果发现TYPE不是标签字符串,而是一个函数(一个类),则会把函数执行(创建类的一个实例),与此同时会把调用组件时候,设置的属性传递给这个函数这个类
  • 调取组件的时候,可以单闭合也可以双闭合,双闭合好处:可以继续在里面写子元素,而单闭合不可以,推荐用双闭合。

组件特点:

给组件传递进来的属性是只读的 (只能获取不能修改) 
1.不能直接的赋值默认值
=>props.title=props.title || "标题"; 不可以
=>let title=props.title || "标题";  可以
2.函数式组件不能像类组件一样,基于prop-types给属性设置默认的规则

类组件:

class xxx extends React.Component/React.PureComponent 当REACT-DOM.RENDER渲染的时候,如果发现虚拟DOM中TYPE是一个类组件,会创建这个类的一个实例,并且把解析处理的PROPS传递给这个类:new Clock (props) =>执行CONSTRUCTOR (此时PROPS并未挂载到实例上,基于this.props不能获取到值,但是可以直接少使用形参中的props;解决方法:super(props)这样在CONSTRUCTOR中也可以使用this.props) super执行,相当于把React.Component当做普通函数执行,让方法中的this是当前实例 this=>{props.xxx,context:xxx,refs:{},updater:{...}}

  • 当CONSTRUCTOR执行完,REACT会帮我们继续处理
    • 把props/context...挂载到实例上 (后期再其它的钩子函数中可以基于THIS.PROPS获取传递的属性值)
    • react帮我们把render方法执行
对于每一个类组件来说,只需学会:
  1. 数据管控
    • 属性 PROPS
    • 状态 STATE (私有状态,redux公共状态管理)
  • 基于第三方插件prop-types设置属性的规则:默认值和其它规则
    • $ yarn add prop-types
  • 设置默认值
    • static defaultProps={ xxx:xxx };
  • 设置一些其它规则
    • static propTypes={ title:PropTypes.string.isRequired };
    • PropTypes.isRequired 必须传递
    • PropTypes.string/number/bool/func/object/symbol/node (元素对象) / element (JSX元素) /instanceOf (Xxx)必须是某个类的实例 /oneOf(['news','Photos'])多个中的一个
  • 和vue一样,我们设定的规则不会阻碍内容的渲染,不符合规则的在控制台报错

REACT与VUE的区别

视图层 vue:template/jsx react:jsx 语法写法 vue:{{}} react:{} 数据层: vue:data vue有一个vm层 Object.defineProperty/Proxy 给数据添加了以下getter/setter方法监听 getter setter 更新先看setter,setter会通知render执行调用 getter方法

react:state 这里需要我们自己在方法里写来通知render执行 setState/forceUpdate 在这里来通知render来执行渲染

非受控组件

不受状态管控 (直接操作DOM) 我们把基于状态 (或者属性) 的更新来驱动视图渲染:“受控组件” (受状态管控的组件) 属性啥时候能改:设置默认值、让父组件重新调取子组件传递不同的属性、把获取的属性赋值给组件的状态,后期修改状态也可以

react生命周期函数

  1. getDefaultProps 处理属性 (获取默认值和校验传递属性的类型 )
  2. getlnitialState 处理状态 (执行CONSTRUCTOR获取初始的状态信息)
  3. componentWillMount:第一次组件渲染之前 =>从服务器获取数据 (把晦气的数据重新赋值给状态或者存放到REDUX中)
  4. render:第一次或者重新进行视图的渲染
  5. componentDidMount:第一次渲染完成
    • 此处可以获取到DOM元素了

更新状态后

  1. shouldComponentUpdate(nextProps , nextState)是否应该更新组件
    • 当我们执行setState等操作,首先触发的是当前钩子函数
      • this.state当前的状态 (改之前的状态)
      • nextState即将要修改的状态信息
      • this.props和nextprops的状态一样的意思
    • 钩子函数返回TRUE代表允许重新渲染视图,反之FALSE则停止进行渲染视图
  2. componentWillUpdate
  3. render
  4. componentDidUpdate
  • 卸载
    • componentWillUnmount 卸载组件

当父组件重新渲染,子组件也会重新渲染,首先触发此钩子函数

  1. componentWillReceiveProps(nextProps)
  2. shouldComponentUpdatee(nextProps , nextState) 是否应该更新组件

执行SET-STATE必然会触发shouldComponentUpdate这个钩子函数,根据TRUE还是FALSSE决定状态是否重新渲染组件 (无论返回啥,状态本身都已经修改了)

  • forceUpdate强制更新 (重新渲染),不会执行shouldComponentUpdate这个钩子函数

第一次渲染TEST视图,会新创建一个CLOCK (执行CLOCK完整生命周期)。当TEST重新渲染的时候,也让CLOCK子组件重新渲染,把最新的属性传递给CLOCK (但不是重新创建),CLOCK中的钩子函数不会从CONSTRUCROR重新执行

REACT中的事件是合成事件

底层源码上是基于事件委托把所有的事件进行代理的 (跨平台、跨终端) =>事件对象也是自己额外单独处理了 SET-STATE在合成事件或者生命周期函数中都是异步操作 + REACT有一个类似于浏览器的渲染队列机制,它会在多次执行SET-STATE的情况下,把其合成一次进行重新渲染 (如果修改的状态一样,以最后一次为主).

SET-STATE同步

把SET-STATE放到一个异步操作中,此时它就没必要异步了,走的是同步处理 + 定时器 + 原生JS事件

REACT中的组件通信

  1. 基于属性传递props
    • 单向数据传递 (父->子)
  2. 子改父 (子组件想通过一些操作把父组件的信息进行修改)
    • 回调函数 (和JSONP或者JSBridge机制类似) :父组件把自身的方法通过属性传递给子组件,子组件在某些情况下,把传递进来的父组件中的方法执行,把子组件中的一些信息传递给方法 (底层:还是基于属性)
    • 我们可以自己写一套eventBus (发布订阅) 一般用于:父子之间,当然祖先和后代之间也可以,只不过需要基于属性一层层的传递 (麻烦),也可以用于兄弟之间,但是需要保证,哥俩有同一个父亲 (亲兄弟)
  3. 执行上下文进行信息传递
    • 把后代中需要的都放到祖先元素的上下文中
    • 后代需要直接获取使用即可
  4. redux/react-redux/dva/redux-saga/mobx...
    • 实现公共状态的管理
  5. 本地存储

REACT中的后代调取祖先

//=>我们一般要把挂载到祖先上下文中的数据放置到祖先的状态上 (后期只需要把祖先的状态改变,上下文中的信息也会跟着改变,同时祖先元素重新渲染,后代元素也要重新渲染,获取最新的上下文信息)
static childContextTypes={
	//=>指定后代能用的公共状态的类型
}
//生命周期函数:给后代提供能用的上下文信息 (公共状态),上面是指定类型,此处是指定具体的值
getChildContext(){
//=>第一次在getIntialState之后执行,每当祖先组件中的状态改变,重新渲染的时候,此钩子函数也会重新渲染被执行
	return{
		xxx:xxx
	}
}
//哪一个后代组件需要用到,直接注册获取使用即可
static contextTypes={
	//想用哪些组件中提供的公共状态,则这块就声明一些它的类型 (要求类型和祖先一致)
}