React.js初探

 

 

React.js

菜鸟官方解释: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 实现了单向响应的数据流,从而减小了重复代码,这也是它为何比传统数据绑定更简单。

Virtual Dom

  • 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生成对应的原生的东西。

Progressive Web Application

字义即:渐进式Web应用

PWA有能够实现什么呢?

  • 能够将app的快捷方式放置到桌面上,全屏运行,与原生app无异

  • 可以在各类网络环境下使用,包括网络差和断网条件下,不会显示undefind

  • 推送消息的能力

  • 其本质是一个网页,没有原生app的各类启动条件,快速响应用户指令

    在React.js中。public文件夹下有一个mainfest.json的文件夹,该文件就是用来实现桌面快捷方式的配置,而无网络状况,或网络状况较差时,则使用service worker来实现离线缓存。

Service Worker

Web离线引用解决方案。指在在进过网页后,当网络断开链接后,依然能够再次访问页面。

ServiceWorker的主要能力集中在网络代理和离线缓存上。具体的实现上,能够理解为ServiceWorker是一个能在网页关闭时仍然运行的WebWorker

在经过react脚手架建立项目后,src根目录下是有一个serviceWorker.js文件的,该文件就是用来写app时,提供离线缓存技术。供线下仍可正常访问。

Immutable

保证state中的数据不被修改。修改数据时,不能经过this.state.xx来就该数据须要用特定的方法this.setState({});能够发现和小程序也是同样的了

JSX

百度解释:

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的虚拟节点的渲染实际上是一致的

className

在设置样式时,咱们原来都是经过添加class或者id来设置对应的类名,在react中由于建立模板时使用的就是class类,因此在渲染模板时,样式的设置能够经过className=""来设置

Fragment

每一个组件都要求有大的标签包裹,可是会产生没必要要的DOM,所以react提供了Fragment来坐占位符。这样就不会产生新的节点,且组件不会抱任何错误。

 import React, { Component,Fragment } form 'react';
 ​
 class Demo extends Component {
     render() {
         return (
           <Fragment>
           Html content
           </Fragment>
         )
     }
 }

dangerouslySetInnerHTML

在render中若是要使某些内容不被转义。

则咱们就须要使用dangerouslySetInnerHTML来保持元素不被转义

 <div dangerouslySetInnerHTML={{ __html: '<div>123</div>' }} />
  1. dangerouslySetInnerHTMl 是React标签的一个属性,相似于angular的ng-bind;

  2. 有2个{{}},第一{}表明jsx语法开始,第二个是表明dangerouslySetInnerHTML接收的是一个对象键值对;

  3. 既能够插入DOM,又能够插入字符串;

  4. 可是存在一个问题,由于使用标签内容后会将其转换,因此颇有可能遭到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标签就会生效。

htmlFor

在使用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中的数据有一个只读属性,是没法作出修改的。若是非要修改,须要父组件传递给子组件一个方法,子组件经过调用该方法来实现数据的更改。

setState

该方法用来更新state数据,调用该方法时,就算state中的数据没有作修改,也会从新执行render方法。

setState({
    isActive: true,
})
console.log(this.state.isActive)//false

该方法实际上是一个异步操做,因此要获得最新的state须要在第二个参数回调函数中获取或者经过async和await来解决啦

async handleClick() {
    await this.setState({
        isActive: true
    })
    console.log(this.state.isActive);//true
}

该方法有两个参数

setState((prevState) => {
    //prevState是旧的数据
},()=> {
    //这里能够获得更新之后的数据
})

PropTypes

组件间传值时,对接受数据的一个限制

详细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,  
}

isRequired

要求该传值对象不能为空,必须有值

组件.propTypes = {
    obj: PropTypes.string.isRequired
}

arrayOf()

要求类型能够为多项

组件.propTypes = {
    obj: PropTypes.arrayOf(PropTypes.number,PropTypes.string)
}

defaultProps

为组件间传值的对象设置默认值

 class 组件 extends Component {}
 组件.defaultProps = {
     obj1: 'hello world'
 }

设置默认值后,父组件在未传递数据时,会默认使用该默认值

后续继续学习更新

相关文章
相关标签/搜索