番外篇:入门React

欢迎关注公众号:n平方
若有问题或建议,请后台留言,我会尽力解决你的问题。

背景

当你以为原生js代码乱七八糟的时候,那就是要体验一下React。(秘籍在最后css

目标

  • 踢开React的大门。

简介

React 的核心思想是:封装组件。
各个组件维护本身的状态和 UI,当状态变动,自动从新渲染整个组件。
React 大致包含下面这些概念:html

  • 组件:
  • JSX
  • Virtual DOM
  • Data Flow

经验:
前端框架的基本组成:
组件及其生命周期、样式、路由、网络请求、数据存储和传递。前端

HelloWorld

import React, { Component } from 'react';
import { render } from 'react-dom';

class HelloMessage extends Component {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

// 加载组件到 DOM 元素 mountNode
render(<HelloMessage name="John" />, mountNode);

解析:node

  • 组件:HelloMessage 就是一个 React 构建的组件,最后一句 render 会把这个组件显示到页面上的某个元素 mountNode 里面,显示的内容就是 <div>Hello John</div>。
  • JSX: 将 HTML 直接嵌入了 JS 代码里面(上面的js里就写了个div),这个就是 React 提出的一种叫 JSX 的语法.
  • Virtual DOM:

虚拟DOM

当组件状态 state 有更改的时候,React 会自动调用组件的 render 方法从新渲染整个组件的 UI。
固然若是真的这样大面积的操做 DOM,性能会是一个很大的问题,因此 React 实现了一个Virtual DOM,组件 DOM 结构就是映射到这个 Virtual DOM 上,React 在这个 Virtual DOM 上实现了一个 diff 算法,当要从新渲染组件的时候,会经过 diff 寻找到要变动的 DOM 节点,再把这个修改更新到浏览器实际的 DOM 节点上,因此实际上不是真的渲染整个 DOM 树。这个 Virtual DOM 是一个纯粹的 JS 数据结构,因此性能会比原生 DOM 快不少。react

  • Data Flow:

“单向数据绑定”是 React 推崇的一种应用架构的方式。webpack

与webpack结合

package.json看依赖git

{
  "name": "learning-01",
  "version": "1.0.0",
  "description": "",
  "main": "webpack.config.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --config ./webpack.config.js --mode development --open",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.3.3",
    "@babel/preset-env": "^7.3.1",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.5",
    "clean-webpack-plugin": "^1.0.1",
    "html-webpack-plugin": "^3.2.0",
    "react-hot-loader": "^4.7.1",
    "webpack": "^4.29.5",
    "webpack-cli": "^3.2.3",
    "webpack-dev-server": "^3.2.0"
  },
  "dependencies": {
    "react": "^16.8.3",
    "react-dom": "^16.8.3"
  }
}

webpack.config.js看配置github

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
    entry: './src/index.js',
    output: {
      path: __dirname + '/dist',
      publicPath: '/',
      filename: 'bundle.js'
    }, module: {
      rules: [
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: ['babel-loader']
        }
      ]
    },
    resolve: {
      extensions: ['*', '.js', '.jsx']
    },
    plugins: [
      new CleanWebpackPlugin(['dist']),
      new webpack.HotModuleReplacementPlugin(),
      new HtmlWebpackPlugin({template:'index.html'})
    ],
    devServer: {
      contentBase: './dist',
      hot: true
    }
  };

基本搭建环境参考(可直接clone)
https://github.com/xbmchina/r...web

JSX

    1. HTML 里的 class 在 JSX 里要写成 className,由于 class 在 JS 里是保留关键字。
  • 2.同理某些属性好比 for 要写成 htmlFor。
  • 3.属性值使用表达式,只要用 {} 替换 ""
// Input (JSX):
var person = <Person name={window.isLoggedIn ? window.name : ''} />;
// Output (JS):
var person = React.createElement(
  Person,
  {name: window.isLoggedIn ? window.name : ''}
);
    1. 使用注释要用 {} 包起来。
{/* child comment, put {} around */}
  • 5.React 会将全部要显示到 DOM 的字符串转义,防止 XSS。
<div dangerouslySetInnerHTML={{__html: 'cc &copy; 2015'}} />
  • 6.属性扩散
var props = {};
props.foo = x;
props.bar = y;
var component = <Component {...props} />;

组件

生命周期(主要两个)

componentWillMount
只会在装载以前调用一次,在 render 以前调用,你能够在这个方法里面调用 setState 改变状态,而且不会致使额外调用一次 render算法

componentDidMount
只会在装载完成以后调用一次,在 render 以后调用,从这里开始能够经过 ReactDOM.findDOMNode(this) 获取到组件的 DOM 节点。

var React = require('react');
var ReactDOM = require('react-dom');
import ComponentHeader from './components/ComponentHeader';
import ComponentFooter from './components/ComponentFooter';
import BodyIndex from './components/BodyIndex';
import BasicExample from './root'

export default class Index extends React.Component {

 constructor(props) {
    super(props);
    this.state = { count: props.initialCount };
  }

  //组件即将加载
  componentWillMount() {
    //定义你的逻辑便可
    console.log("Index - componentWillMount");
  }
  //组件加载完毕
  componentDidMount() {
    console.log("Index - componentDidMount");
  }

  render() {

        /*
        var component;
        if (用户已登陆) {
            component = <ComponentLoginedHeader/>
        }
        else{
            component = <ComponentHeader/>
        }
        */

    return (
      <div>
        <ComponentHeader />
        <BodyIndex />
        <ComponentFooter />
      </div>
    );
  }
}

ReactDOM.render(<BasicExample/>,document.getElementById('app'))
事件处理

给事件处理函数传递额外参数的方式:bind(this, arg1, arg2, ...)

render: function() {
    return <p onClick={this.handleClick.bind(this, 'extra param')}>;
},
handleClick: function(param, event) {
    // handle click
}
DOM操做

Refs
另一种方式就是经过在要引用的 DOM 元素上面设置一个 ref 属性指定一个名称,而后经过 this.refs.name 来访问对应的 DOM 元素。

好比有一种状况是必须直接操做 DOM 来实现的,你但愿一个 <input/> 元素在你清空它的值时 focus,你无法仅仅靠 state 来实现这个功能。

class App extends Component {
  constructor() {
    return { userInput: '' };
  }

  handleChange(e) {
    this.setState({ userInput: e.target.value });
  }

  clearAndFocusInput() {
    this.setState({ userInput: '' }, () => {
      this.refs.theInput.focus();
    });
  }

  render() {
    return (
      <div>
        <div onClick={this.clearAndFocusInput.bind(this)}>
          Click to Focus and Reset
        </div>
        <input
          ref="theInput"
          value={this.state.userInput}
          onChange={this.handleChange.bind(this)}
        />
      </div>
    );
  }
}
组合组件

使用组件的目的就是经过构建模块化的组件,相互组合组件最后组装成一个复杂的应用。在 React 组件中要包含其余组件做为子组件,只须要把组件看成一个 DOM 元素引入就能够了。

var React = require('react');
var ReactDOM = require('react-dom');
import ComponentHeader from './components/ComponentHeader';
import ComponentFooter from './components/ComponentFooter';
import BodyIndex from './components/BodyIndex';

class Index extends React.Component {
  //组件即将加载
  componentWillMount() {
    //定义你的逻辑便可
    console.log("Index - componentWillMount");
  }
  //组件加载完毕
  componentDidMount() {
    console.log("Index - componentDidMount");
  }

  render() {

        /*
        var component;
        if (用户已登陆) {
            component = <ComponentLoginedHeader/>
        }
        else{
            component = <ComponentHeader/>
        }
        */

    return (
      <div>
        <ComponentHeader />
        <BodyIndex />
        <ComponentFooter />
      </div>
    );
  }
}


ReactDOM.render(
  <Index />, document.getElementById('app'));
组件间通讯

父子组件间通讯

  • 1.父组件传递到子组件:

就是经过 props 属性传递,在父组件给子组件设置 props,而后子组件就能够经过 props 访问到父组件的数据/方法,这样就搭建起了父子组件间通讯的桥梁。

  • 2.父组件访问子组件?
    用 refs

非父子组件间的通讯
使用全局事件 Pub/Sub 模式,在 componentDidMount 里面订阅事件,在 componentWillUnmount 里面取消订阅,当收到事件触发的时候调用 setState 更新 UI。
通常来讲,对于比较复杂的应用,推荐使用相似 Flux 这种单项数据流架构

使用css样式

1.内联样式

在render函数里定义

const styleComponentHeader = { header: { backgroundColor: '#333333', color: '#FFFFFF', 'padding-top': '12px', 'paddingBottom: '16px' } };

注意样式的驼峰写法 style = {styleComponentHeader.header}

文件中引用css的样式 注意class须要更改为className肯定是动画、伪类(hover)等不能使用

2.内联样式中的表达式

paddingBottom:(this.state.minHeader)?"3px":"15px"

注意好好理解这里的state引发样式的即时变化

3.CSS模块化

缘由:避免全局污染、命名混乱、依赖管理不完全、没法共享变量、代码压缩不完全

npm install --save-dev style-loader css-loader npm install --save-dev babel-plugin-react-html-attrs  //为了使用原生的html属性名

全局样式和局部样式

:local(.normal){color:green;}  //局部样式
:global(.btn){color:red;}  //全局样式

CSS模块化的优势 全部样式都是local的,解决了命名冲突和全局污染问题 class名生成规则配置灵活,能够此来压缩class名 只需引用组件的JS就能搞定组件全部的js和css 依然是css,几乎零学习成本

jsx样式与css的互转 工具:https://staxmanade.com/CssToReact/

react-router

官网:https://reacttraining.com/rea...
GitHub:https://github.com/ReactTrain...

注意点:
1.引用的包是有区别的。

2.控制页面的层级关系 单页面构建Router控制
底层机制 React: state/props -> Components ->UI Router: location ->Router -> UI

3.router传参
定义: path="list/:id" 使用: this.props.match.params.id

4.地址没法刷新(巨坑)
表现:'/' 根节点 Home 显示无误,不过其余任何路由 例如 /detail,均显示 Cannot GET /detail。
解决方法:

  • 4.1 用的 BrowserRouter 改成 HashRouter 便可
  • 4.2 修改 webpack.config.js 配置文件
module.exports = {
    // 省略其余的配置
    devServer: {
        historyApiFallback: true
    }
}

详情能够参考:https://blog.csdn.net/zwkkkk1...

网络请求Fetch

官网:https://github.com/github/fetch

fetch('/users.json')
  .then(function(response) {
    return response.json()
  }).then(function(json) {
    console.log('parsed json', json)
  }).catch(function(ex) {
    console.log('parsing failed', ex)
  })

Redux

下期再讲

学习资料


练习代码
学习Demo样例:https://github.com/xbmchina/r...
项目Demo样例:https://github.com/xbmchina/r...


React相关资料

**React官网:https://reactjs.org/docs/hell...
React中文网:https://react.docschina.org/
React学习文档:http://caibaojian.com/react/
webpack搭建React:https://segmentfault.com/a/11...
React-router官网:https://reacttraining.com/rea...
阿里UI库Ant Design:https://ant.design/index-cn
阿里图标库:https://www.iconfont.cn/
谷歌的ReactUI库:https://material-ui.com/
css转React:https://staxmanade.com/CssToR...
Fetch请求:https://github.com/github/fetch**

最后

本人水平有限,欢迎各位建议以及指正。顺便关注一下公众号呗,会常常更新文章的哦。
n平方

相关文章
相关标签/搜索