Raect

React虚拟DOM概念虚拟DOM的结构

  • 在传统的 Web 应用中,我们往往会把数据的变化实时地更新到用户界面中,于是每次数据的微小变动都会引起 DOM 树的重新渲染。如果当前 DOM 结构较为复杂,频繁的操作很可能会引发性能问题。React 为了解决这个问题,引入了虚拟 DOM 技术。

  • 虚拟 DOM 是一个 JavaScript 的树形结构,包含了 React 元素和模块。组件的 DOM 结构就是映射到对应的虚拟 DOM 上,React 通过渲染虚拟 DOM 到浏览器,使得用户界面得以显示。与此同时,React 在虚拟的 DOM 上实现了一个 diff 算法,当要更新组件的时候,会通过 diff 寻找到要变更的 DOM 节点,再把这个修改更新到浏览器实际的 DOM 节点上,所以在 React 中,当页面发生变化时实际上不是真的渲染整个 DOM
  • React 虚拟 DOM 中的诸多如 div 一类的标签与实际 DOM 中的 div 是相互独立的两个概念,它是一个纯粹的 JS 数据结构,它只是提供了一个与 DOM 类似的 Tag 和 API。React 会通过自身的逻辑和算法,转化为真正的 DOM 节点。也正是因为这样的结构,虚拟 DOM 的性能要比原生 DOM 快很多。

HTML标签与React组件

  • React可以直接渲染HTML类型的标签,也可以渲染React的组件
  • HTML类型的标签第一个字母用小写来写表示。
import React from 'react';
//当一个标签里面为空的时候,可以直接使用自闭和标签
//注意class是一个JavaScript保留字,所以如果class应该替换成className
let divElement = <div className="foo"/>;
//等同于
let divElement = React.createElement('div',{className:'foo'});复制代码
  • React组件标签第一个字母大写。
import React from 'react';
class Headline extends React.component{
  ...
  render(){
    //直接return JSX语法
    return <h1>Hello React</h1>
  }
}
let Headline = <Headline />;
let headline = React.createElement(Headline);复制代码
  • JSX语法使用第一个字母大小写来区分是一个普通的HTML标签还是一个React组件
  • 注意:因为JSX本身是JavaScript语法,所以一些JavaScript中的保留字要用其他的方式书写,比如第一个例子中class要写成className



State属性state状态

  • state 是组件内部的属性。组件本事是一个状态机,它可以在constructor中通过this.state直接定义它的值,然后根据这些值来渲染不同的UI。当state的值发生改变时,可以通过this.setState方法让组件再次调用render方法,来渲染新的UI。当state的值发生改变时,可以通过this.setState方法再次调用render方法,来渲染新的UI。

state设计原则

  • 什么组件应该有State,而且应该遵循最小化state的准则?那就是尽量让大多数的组件都是无状态的。为了实现这样的结构,因该尽量把状态分离在一些特定的组件中,来降低组件的复杂程度。最常见的做法就是创建尽力那个多的无状态组件,这些组件唯一要关心的事情就是渲染数据。而在这些组件的外层,应该有一个包含state的父级的组件。这个组件用于处理各种事件、交流逻辑、修改state、对应的子组件要关心的只是传入的属性而已
  • state 应该包含什么数据? state中应该包含组件的事件回调函数可能引发UI更新的这类数据。在实际的项目中,这些应该是轻量化的JSON数据,应该尽量把数据的表现设计到最小,而更多的数据可以在render方法通过各种计算来得到。这里举一个例子,比如说现在有一个商品列表,还有一个用户已经选购的商品列表,最直观的设计方法如下:
{
  goods:[
    {
      "id":1,
      "name":"paper"
    },
    {
      "id":2,
      "name":"pencil"
    }
    ...
  ],
  selectedGoods:[
    {
      "id":1,
      "name":"hello world"
    }
  ],
}复制代码
  • 这样做当然可以,但根据最小化设计state原则,还是有更好的方法!!!
  • selectedGoods 的商品就是goods里面的几项,数据是完全一致的,所以说这里只需要保存ID,就可以完成同样的功能。所以可以修改成如下。
selectedGoods:[1,2,3]复制代码
  • 在渲染这个组件的时候,只需要把要渲染的条目从goods中取出来就可以了。
  • state不应该包含什么数据?就像上面的例子所描述的一样,为了达到state的最小化,下面?几种数据不应该包含在state
    • 可以由state计算出的数据。就像selectedGoods一样,可以由goods列表计算得出。
    • 组件。组件不需要保存到state中,只需要在render方法中渲染。
    • props中的数据。props可以看作是组件的数据来源,它不需要保存在state中。



事件与数据的双向绑定

  • bodyIndex.js代码
import React from 'react';
import BodyChild from './bodychild'
export default class BodyIndex extends React.Component {
  constructor() {
    super(); //调用基类的所有的初始化方法
    this.state = {
      username: "Parry",
      age:20
    };//初始化赋值
  }

  handleChildValueChange(event){
    this.setState({age:event.target.value});//取出子页面的值
  }

  changeUserInfo(){
    this.setState({age:50});
  };

  render() {
    return (
      <div>
        <h2>页面主题内容</h2>
        <p>{this.state.username} {this.state.age} {this.props.userid} {this.props.username}</p>
        <p>age: {this.state.age}</p>
        <input type="button" value="提交" onClick={this.changeUserInfo.bind(this)}/>
        <BodyChild handleChildValueChange={this.handleChildValueChange.bind(this)}/>
      </div>
    )
  }
}
复制代码
  • bodychild.js代码
import React from 'react';
export default class BodyChild extends React.Component{

  render() {
    return(
      <div>
        <p>子页面输入:<input type="text" onChange={this.props.handleChildValueChange}/></p>
      </div>
    )
  }
}
复制代码
  • 通过在子页面BodyChild设置props,子页面value改变调用handleChildValueChange,传值到父页面bodyIndex。也就是说在子页面中通过调用父页面传递过来的事件props进行组件间的参数传递。
  • 思考(onChange与onBlur)的对比。
  • ES6的语法注意
    • 函数绑定方法this :this.forceUpdateHander = this.forceUpdateHander.bind(this)
    • 或者调用时绑定:onClick={this.changeUserInfo.bind(this,50)}

组件Refs(操作DOM的2⃣️两种方法)

  • 第一种方式
var mySubmitButton = document.getElementById('submitButton');
console.log(mySubmitButton);
ReactDOM.findDOMNode(mySubmitButton).style.color = 'red';
//不推荐此方法,有安全隐患,XSS攻击复制代码
  • 第二种方法
console.log(this.refs.submitButton);
this.refs.submitButton.style.color = 'red';复制代码



独立组件间共享 Mixins

  • ES6不支持Mixin,所以需要相插件来进行支持,npm install --save react-mixin@2
  • 测试一下Mixin是如何运行的
  • src/js/components下创建mixins.js
const MixinLog = {
  componentDidMount(){
    console.log("MixinLog componentDidMount");//查看Mixin生命周期
  },
  log(){
    console.log("abcdefg");
  }
};

export default MixinLog //向外输出
复制代码
  • 在bodyIndex.js中
import React from 'react';
import ReactDOM from 'react-dom';
import BodyChild from './bodychild';
import ReactMixin from 'react-mixin';
import MixinLog from './mixins';

  changeUserInfo() {
    ...
    MixinLog.log();
  };

  render() {
    ...
    <input id="submitButton" ref="submitButton" type="button" value="提交" onClick={this.changeUserInfo.bind(this, 99)}/>
    ...
  }

BodyIndex.defaultProps = defaultProps;

ReactMixin(BodyIndex.propTypes,MixinLog);复制代码
  • 点击页面上的提交按钮?在console.log中会出现MixinLog componentDidMountabcdefg




React 內联式样

  • 通过header.js演示JSX样式控制,直接內联到标签中的style
import React from 'react';
export default class CompomentHeader extends React.Component{

  render(){
    const styleComponentHeader = {
      header: {
        backgroundColor: "#333333",
        color: "#ffffff",
        "padding-top": "15px",
        paddingBottom: "15px"
      }
      //还可以定义其他的样式
    }
    return(
      <header style={styleComponentHeader.header}>
        <h1>这里是表头</h1>
      </header>
    )
  }
}复制代码
  • React上不是很适合此方法,hover等一些动画或者伪类,但在移动开发ReactNative中会常用。

采用原始引用方式

  • header添加为<header style={styleComponentHeader.header} className="smallFintSize">,并在index.html引用相关css
  • 不好在于污染全局

內联式样中的表达式

import React from 'react';
export default class CompomentHeader extends React.Component{

  constructor(){
    super();
    this.state ={
      miniHeader:false //默认加载的时候还是高(不是mini)的头部
    };
  };

  switchHeader(){
    this.setState({
      miniHeader: !this.state.miniHeader //对state进行取反
    });
  };

  render(){
    const styleComponentHeader = {
      header: {
        backgroundColor: "#333333",
        color: "#ffffff",
        "padding-top": (this.state.miniHeader) ? "3px" : "15px",
        paddingBottom: (this.state.miniHeader) ? "3px" : "15px"
      },
      //还可以定义其他的样式
    };
    return(
      <header style={styleComponentHeader.header} className="smallFintSize" onClick={this.switchHeader.bind(this)}>
        <h1>这里是表头</h1>
      </header>
    )
  }
}复制代码



CSS模块化

  • "babel-plugin-react-html-attrs": "^2.0.0"让JSX中className能变回原来class
  • webpack要重新配置
// webpack.config.js
var webpack = require("webpack");
var path = require("path");

module.exports = {
  devtool: 'source-map',
  context: path.resolve(__dirname, "src"),
  entry: "./js/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: 'bundle.js' // 打包输出的文件
  },
  module: {
    rules: [{
        test: /\.js$/, // test 去判断是否为.js或.jsx,是的话就是进行es6和jsx的编译
        exclude: /(node_modules)/,
        use: [{
          loader: 'babel-loader',
          //配置参数;
          options: {
            presets: ['es2015', 'react'],
            plugins: ['react-html-attrs']
          }
        }, ]
      },
      {
        test: /\.css$/,
        use: [{
          loader: 'style-loader',
        }, {
          loader: 'css-loader',
          options: {
            modules: true,
            localIdentName: '[path][name]__[local]--[hash:base64:5]'
          }
        }]
      },
    ]
  },
};
复制代码
  • src/css下,创建一个footer.css,此css设置初衷是为了单独去渲染footer,希望footer.css不会污染全局,但通常情况下全局引用css是会污染全局的,内容如下
.miniFooter {
  background: #333333;
  color: #ffffff;
  padding-left: 20px;
  padding-top: 3px;
  padding-bottom: 3px;
}
.miniFooter h1 {
  font-size: 15px;
}复制代码
  • 在footer.js下写
import React from 'react';

var footerCss = require("../../css/footer.css");//引入css

export default class CompomentFooter extends React.Component{
  render(){
    console.log(footerCss);
    return(
      <footer class={footerCss.miniFooter}>//通过var footerCss 选取footer.css中miniFooter
      <h1>这里是尾部</h1>
      </footer>
    );
  }
}复制代码
  • 因为我们在打包时设置了localIdentName:'[path][name]__[local]--[hash:base64:5]',这地方就是引用css的路径限制。
  • 默认情况下,CSS 将所有的类名暴露到全局的选择器作用域中。样式可以在局部作用域中,避免全局作用域的样。详细?请查看官方文档官方文档式
  • 所以在浏览器中console出了Object {miniFooter: "css-footer__miniFooter--2W_7G"}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值