番外篇:入门React

栏目: IOS · Android · 发布时间: 5年前

内容简介:欢迎关注公众号:n平方当你觉得原生js代码乱七八糟的时候,那就是要体验一下React。(React 的核心思想是:封装组件。

欢迎关注公众号:n平方

背景

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

目标

  • 踢开React的大门。

简介

React 的核心思想是:封装组件。

各个组件维护自己的状态和 UI,当状态变更,自动重新渲染整个组件。

React 大体包含下面这些概念:

  • 组件:
  • 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);

解析:

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

番外篇:入门React

当组件状态 state 有更改的时候,React 会自动调用组件的 render 方法重新渲染整个组件的 UI。

当然如果真的这样大面积的操作 DOM,性能会是一个很大的问题,所以 React 实现了一个Virtual DOM,组件 DOM 结构就是映射到这个 Virtual DOM 上,React 在这个 Virtual DOM 上实现了一个 diff 算法,当要重新渲染组件的时候,会通过 diff 寻找到要变更的 DOM 节点,再把这个修改更新到浏览器实际的 DOM 节点上,所以实际上不是真的渲染整个 DOM 树。这个 Virtual DOM 是一个纯粹的 JS 数据结构,所以性能会比原生 DOM 快很多。

  • Data Flow:

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

与webpack结合

package.json看依赖

{
  "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看配置

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...

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 © 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.引用的包是有区别的。

番外篇:入门React

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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

从“为什么”开始

从“为什么”开始

[美] 西蒙·斯涅克 / 苏西 / 海天出版社 / 2011-7 / 32.00元

影响人类的行为:要么靠操纵,要么靠感召。 操纵带来的是交易,是短期效益; 感召带来的是信任,是永续经营! 盖茨走后,微软面临怎样的挑战?后盖茨时代,微软为何从一个希望改变世界的公司沦落为一个做软件的公司? 沃尔玛的灵魂人物过世后,一度被人们热爱的公司,遭到的竟然多是顾客、员工的反感?沃尔玛要怎样做才能重放昔日光彩? 星巴克吸引人们购买的不是咖啡,而是理念?为什么说霍华......一起来看看 《从“为什么”开始》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

MD5 加密
MD5 加密

MD5 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试