菜鸟官方解释:css
React 是一个用于构建用户界面的 JAVASCRIPT 库。html
React主要用于构建UI,不少人认为 React 是 MVC 中的 V(视图)。vue
React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。react
React 拥有较高的性能,代码逻辑很是简单,愈来愈多的人已开始关注和使用它android
React特色:ios
1.声明式设计 −React采用声明范式,能够轻松描述应用。json
2.高效 −React经过对DOM的模拟,最大限度地减小与DOM的交互。小程序
3.灵活 −React能够与已知的库或框架很好地配合。浏览器
4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不必定使用 JSX ,但咱们建议使用它。缓存
5.组件 − 经过 React 构建组件,使得代码更加容易获得复用,可以很好的应用在大项目的开发中。
6.单向响应的数据流 − React 实现了单向响应的数据流,从而减小了重复代码,这也是它为何比传统数据绑定更简单。
state建立数据
jsx 模板
数据 + 模板 生成Virtual DOM(虚拟节点就是js建立的一个对象,该对象是对节点的一个描述,包含了该节点的全部信息,attrs,content等)
用虚拟DOM生成真实的DOM,显示
state改变
数据 + 模板生成新的 Virtual DOM
对比新旧Virtual DOM的区别,找到区别。
直接操做DOM改变有区别的地方。
注:由于浏览器在解析网页时,js和html是分开的。就至关于两个模块,js要跨越界限操道别人的东西,因此说代价是比较大的。虚拟dom的建立使得性能很大程度提高,且他的应用 使得跨端应用得意实现 React Native.在android和ios端是不存在dom一说的,因此在建立虚拟dom后,会将虚拟dom生成对应的原生的东西。
字义即:渐进式Web应用
PWA有能够实现什么呢?
能够将app的快捷方式放置到桌面上,全屏运行,与原生app无异
可以在各类网络环境下使用,包括网络差和断网条件下,不会显示undefind
推送消息的能力
其本质是一个网页,没有原生app的各类启动条件,快速响应用户指令
在React.js中。public文件夹下有一个mainfest.json的文件夹,该文件就是用来实现桌面快捷方式的配置,而无网络状况,或网络状况较差时,则使用service worker来实现离线缓存。
Web离线引用解决方案。指在在进过网页后,当网络断开链接后,依然能够再次访问页面。
ServiceWorker的主要能力集中在网络代理和离线缓存上。具体的实现上,能够理解为ServiceWorker是一个能在网页关闭时仍然运行的WebWorker
在经过react脚手架建立项目后,src根目录下是有一个serviceWorker.js文件的,该文件就是用来写app时,提供离线缓存技术。供线下仍可正常访问。
保证state中的数据不被修改。修改数据时,不能经过this.state.xx来就该数据须要用特定的方法this.setState({});能够发现和小程序也是同样的了
百度解释:
JSX是一种JavaScript的语法扩展,运用于React架构中,其格式比较像是模版语言,但事实上彻底是在JavaScript内部实现的。元素是构成React应用的最小单位,JSX就是用来声明React当中的元素,React使用JSX来描述用户界面。
详细使用:JSX
render() { return ( <div> <ul> <li></li> </ul> </div> ) }
上面代码等同于下面
render() { return React.createElement('div',{},React.createElement('ul',{},React.craeteElement('li',{}))); }
他的顺序:jsx => createElement => Virtual Dom => 真实Dom
vue和react的虚拟节点的渲染实际上是一致的
在设置样式时,咱们原来都是经过添加class或者id来设置对应的类名,在react中由于建立模板时使用的就是class类,因此在渲染模板时,样式的设置能够经过className=""来设置
每一个组件都要求有大的标签包裹,可是会产生没必要要的DOM,所以react提供了Fragment来坐占位符。这样就不会产生新的节点,且组件不会抱任何错误。
import React, { Component,Fragment } form 'react'; class Demo extends Component { render() { return ( <Fragment> Html content </Fragment> ) } }
在render中若是要使某些内容不被转义。
则咱们就须要使用dangerouslySetInnerHTML来保持元素不被转义
<div dangerouslySetInnerHTML={{ __html: '<div>123</div>' }} />
dangerouslySetInnerHTMl 是React标签的一个属性,相似于angular的ng-bind;
有2个{{}},第一{}表明jsx语法开始,第二个是表明dangerouslySetInnerHTML接收的是一个对象键值对;
既能够插入DOM,又能够插入字符串;
可是存在一个问题,由于使用标签内容后会将其转换,因此颇有可能遭到XSS攻击。
import React,{ Component,Fragment } from 'react'; import './style/todoList.css' class TodoList extends Component { constructor(props) { super(props); this.state = { inputValue: '', list: [] } this.handleInputChange = this.handleInputChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } render() { return ( <Fragment> {/**这里是注释 */} <input className="input" onChange={this.handleInputChange.bind(this)} value={this.state.inputValue} /> <button className="btn" onClick={this.handleSubmit}>提交</button> <ul> { this.state.list.map((item,index) => { return ( <li key={index} onClick={this.handleDeleteItem.bind(this,index)} dangerouslySetInnerHTML={{__html:item}} > </li> ) }) } </ul> </Fragment> ) }; handleInputChange(e) { this.setState({ inputValue: e.target.value }) }; handleSubmit() { this.setState({ list: [...this.state.list,this.state.inputValue], inputValue: '' }) }; handleDeleteItem(index) { let list = [...this.state.list]; list.splice(index,1); this.setState({ list: list }) } } export default TodoList;
当咱们在input中输入<h1>Hello World</h1>时,若是使用了dangerouslySetInnerHTML的话,h1标签就会生效。
在使用label时,通常咱们会经过for与input上的id进行绑定。在react中,咱们则须要经过htmlFor=""来绑定input
父传子经过属性传递,将须要传递的数据放在子组件上,经过属性的方式传递,子组件经过this.props.attr则就能够获取到父组件传递过来的数据
父组件:
import TodoItem from './TodoItem' render() { return ( <ul> { this.state.list.map((item,index) => { return ( <div> <TodoItem content={item} index={index} /> {/*<li key={index} onClick={this.handleItemDelete.bind(this,index)} dangerouslySetInnerHTML={{__html:item}} > </li>*/} </div> ) }) } </ul> ) }
给子组件将数据挂在到content和index上,
import React, { Component } from "react"; class TodoItem extends Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } render() { return ( <div>{this.props.content}</div> ) } } export default TodoItem;
经过this.props就能够获取到父组件传递过来的数据。
子传父的话,没有vue那么多的方法,这里须要在父组件先将方法传递给子组件。
将方法经过属性的方式挂在到子组件上,不过须要注意的是,这里须要绑定指向为父组件
仍是刚才的内容
import React,{ Component,Fragment } from 'react'; import TodoItem from './TodoItem'; import './style/todoList.css'; class TodoList extends Component { constructor(props) { super(props); this.state = { inputValue: '', list: [] } this.handleInputChange = this.handleInputChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleItemDelete = this.handleItemDelete.bind(this); } render() { return ( <Fragment> <div> <label htmlFor="inputArea">输入内容</label> <input id="inputArea" className="input" onChange={this.handleInputChange} value={this.state.inputValue} /> <button className="btn" onClick={this.handleSubmit} >提交</button> </div> <ul> {this.getTodoItem()} </ul> </Fragment> ) }; getTodoItem() { return this.state.list.map((item,index) => { return ( <TodoItem key={index} content={item} index={index} deleteItem={this.handleItemDelete} /> ) }) }; handleInputChange(e) { const value = e.target.value; this.setState(() => ({ inputValue: value })) }; handleSubmit() { this.setState((prevState) => ({ list: [...prevState.list,prevState.inputValue], inputValue: '' })) }; handleItemDelete(index) { this.setState((prevState) => { const list = [...prevState.list]; list.splice(index,1); return {list} }) } } export default TodoList;
deleteItem就是挂在的方法,供子组件调用
子组件
import React, { Component } from "react"; class TodoItem extends Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } render() { const { content }= this.props; return ( <div onClick={this.handleClick}> {content} </div> ) } handleClick() { const { deleteItem,index } = this.props; deleteItem(index); } } export default TodoItem;
注:react是单向数据流,举这样一个例子:父组件引用了5个子组件,每一个子组件都引用了父组件传递的list.若是不是单向数据流,子组件在对this.props.list= [];作出修改后,其余4个子组件会怎样?
显示这就是一个bug了,修改一个其余的都修改了。显然是一个比较严重的问题。因此react单向数据里就是解决这样一个问题。
父组件传递给子组件的数据,是没法作出修改的。state中的数据有一个只读属性,是没法作出修改的。若是非要修改,须要父组件传递给子组件一个方法,子组件经过调用该方法来实现数据的更改。
该方法用来更新state数据,调用该方法时,就算state中的数据没有作修改,也会从新执行render方法。
setState({ isActive: true, }) console.log(this.state.isActive)//false
async handleClick() { await this.setState({ isActive: true }) console.log(this.state.isActive);//true }
该方法有两个参数
setState((prevState) => { //prevState是旧的数据 },()=> { //这里能够获得更新之后的数据 })
组件间传值时,对接受数据的一个限制
详细doc可查看官网https://reactjs.org/docs/typechecking-with-proptypes.html
import { PropTypes } from 'prop-types' class 组件 extends Component {} 组件.propTypes = { optionalArray: PropTypes.array, optionalBool: PropTypes.bool, optionalFunc: PropTypes.func, optionalNumber: PropTypes.number, optionalObject: PropTypes.object, optionalString: PropTypes.string, optionalSymbol: PropTypes.symbol, }
组件.propTypes = {
obj: PropTypes.string.isRequired
}
要求类型能够为多项
组件.propTypes = {
obj: PropTypes.arrayOf(PropTypes.number,PropTypes.string)
}
为组件间传值的对象设置默认值
class 组件 extends Component {} 组件.defaultProps = { obj1: 'hello world' }
设置默认值后,父组件在未传递数据时,会默认使用该默认值
后续继续学习更新