zoukankan      html  css  js  c++  java
  • React.js初探

     

     

    React.js

    菜鸟官方解释:

    React 是一个用于构建用户界面的 JAVASCRIPT 库。

    React主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图)。

    React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。

    React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使用它

    React特点:

    • 1.声明式设计 −React采用声明范式,可以轻松描述应用。

    • 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'
     }

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

    后续继续学习更新

  • 相关阅读:
    N75终于可以发彩信了
    用OpenSSL编写SSL,TLS程序(转)
    分享 jdk ant 绿色安装及自动化配置 for windows
    Symbian: How to write HBufC* to file(转)
    [转载]用非对称密码算法制作共享软件的注册码
    [笔记]远程终端API,Terminal Services Administration
    [转载]共享软件的注册加密法
    [希腊神话] 3Apollo(阿波罗,太阳神) [English Edition][附译文]
    [转载]软件加密技术和注册机制
    [希腊神话] 5Nereus and Proteus(纳鲁斯和普鲁吐斯,海神) [English Edition][附译文]
  • 原文地址:https://www.cnblogs.com/bgwhite/p/10948693.html
Copyright © 2011-2022 走看看