当前位置: 首页 > 工具软件 > gulp-tutorial > 使用案例 >

React.js读书与总结:《react-tutorial》

孙乐逸
2023-12-01

最近接触的一个项目中使用了React为主要框架,虽然之前也多多少少学过一些React,但是还需要更深入的学习和更熟练的掌握,所以最近我打算好好的读上几本React的书,今天带来第一本书:《react-tutorial》的学习总结。

前言

技术在没有真正使用之前,没法评价哪一个好,没有最好的,只有最合适的。

一 Webpack 配置 React 开发环境

搭建一个现代的前端开发环境配套的工具有很多,比如 Grunt / Gulp / Webpack / Broccoli,
这些都是要解决前端工程化问题。

而ES6 编译工具 Babel,则内置了对 JSX 语法的支持。

(1)Webpack简介:

前端资源加载/打包工具,只需简单的配置就可提供前端工程化需要的各种功能,
如有需要还可被整合到其他如 Grunt / Gulp 的工作流

(2)webpack 的优势:

  1. 以 commonJS 的形式来书写脚本,对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。
  2. 能被模块化的不仅仅是 JS 。
  3. 开发便捷,能替代部分 grunt/gulp 的工作,比如打包、压缩混淆、图片转base64等。
  4. 扩展性强,插件机制完善

(3)安装 Webpack:

npm install -g webpack

使用 webpack.config.js 配置文件

要编译 JSX,先安装对应的 loader: npm install babel-loader –save-dev

(4)webpack配置

webpack配置与使用可参考:
http://www.cnblogs.com/vajoy/p/4650467.html
http://www.jianshu.com/p/b95bbcfc590d

详细了解:
webpack官网: http://webpack.github.io/
文档地址: http://webpack.github.io/docs/

module下的loaders 是最关键的一块配置,它告知 webpack 每一种文件都需要使用什么加载器来处理。

webpack所有的loader列表和使用方法可参考:http://webpack.github.io/docs/list-of-loaders.html

二 JSX

(1)为什么要引入 JSX 这种语法?

传统的 MVC 是将模板放在其他地方,比如 script 标签或者模板文件,再在 JS 中通过某种手段引用模板。按这种思路,想想多少次我们面对四处分散的模板片段不知所措?纠结模板引擎,纠结模板存放位置,纠结如何引用模板。

React 认为组件才是王道,而组件是和模板紧密关联的,组件模板和组件逻辑分离让问题复杂化了。所以就有了 JSX 这种语法,就是为了把 HTML 模板直接嵌入到 JS 代码里面,这样就做到了模板和组件关联,但是 JS 不支持这种包含 HTML 的语法,所以需要通过工具将 JSX 编译输出成 JS 代码才能使用。

(2)JSX基本语法

1.小写的字符串是 HTML 标签,大写开头的变量是 React 组件。

2.HTML 里的 class 在 JSX 里要写成 className,因为 class 在 JS 里是保留关键字。同理某些属性比如 for 要写成 htmlFor。

3.表达式
属性值使用表达式,只要用 {} 替换 “”。

表达式是非常强大的,我们可以使用它在JSX标签间或属性中放置js的各种表达式或函数实现各种功能。

子组件也可以作为表达式使用,如:

// Input (JSX):
var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
// Output (JS):
var content = React.createElement(
  Container,
  null,
  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
);

4.JSX注释:
在< >内部可使用js的注释,如果在一个组件的子元素位置使用注释要用 {} 包起来。

5.自定义 HTML 属性:
如果在 JSX 中使用的属性不存在于 HTML 的规范中,这个属性会被忽略。如果要使用自定义属性,可以用 data- 前缀。

6.属性扩散:
使用es6的写法,可给组件设置多个属性,如:

var props = {};
props.foo = x;
props.bar = y;
var component = <Component {...props} />;
props 对象的属性会被设置成 Component 的属性。

另外,jsx中:
style 属性接受由 CSS 属性构成的 JS 对象
onChange 事件表现更接近我们的直觉(不需要 onBlur 去触发)

(3)组件

组件的两个核心概念:props和state。

1.props

props 即组件的属性,由外部通过 JSX 属性传入设置,一旦初始设置完成,就可以认为 this.props 是不可更改的,所以不要轻易更改设置 this.props 里面的值(虽然对于一个 JS 对象你可以做任何事)。

2.state
state 即组件的当前状态,可以把组件简单看成一个“状态机”,
根据状态 state 呈现不同的 UI 展示。一旦状态(数据)更改,组件就会自动调用 render 重新渲染 UI,这个更改的动作会通过 this.setState()来触发。

划分状态的原则:让组件尽可能地少状态,便于组件易维护。

当更改某个数据需要更新组件 UI 的就可以认为是 state。

3.无状态组件

也可以用纯粹的函数定义无状态组件(没有状态和生命周期,只简单的接受 props 渲染生成 DOM 结构)。

无状态组件非常简单,开销低,可能的话尽量去使用无状态组件。比如使用箭头函数定义

const HelloMessage = (props) => <div> Hello {props.name}</div>;
render(<HelloMessage name="John" />, mountNode);

因为无状态组件只是函数,没有实例返回,这点在想用 refs 获取无状态组件的时候要注意。

4.组件生命周期

1.初始化 this.state 的值,只在组件加载之前调用一次。

ES6中可以在构造函数中初始化状态,如:

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { count: props.initialCount };
  }

  render() {
    // ...
  }
}

2.加载(渲染)组件触发的生命周期函数:

componentWillMount()
只在加载之前调用,在 render 之前调用,可以在这个方法里面调用 setState 改变状态,并且不会导致额外调用一次 render

componentDidMount()
只在加载完成之后调用,在 render 之后调用,从这里开始可以通过 ReactDOM.findDOMNode(this) 获取到组件的 DOM 节点。

3.更新(重新渲染)组件触发的生命周期函数:

这些方法不会在首次 render 组件的周期调用。

componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate

4.卸载组件触发的生命周期函数:

componentWillUnmount

(4)React事件处理

1.绑定事件

例:


...

handleClick(e) {
    this.setState({ liked: !this.state.liked });
  }

  render() {
    const text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick.bind(this)}>
          You {text} this. Click to toggle.
      </p>
    );
  }

...

React 里面绑定事件的方式和在 HTML 中绑定事件类似,使用驼峰式命名指定要绑定的事件类型(比如 onClick)属性为组件定义的一个方法如( {this.handleClick.bind(this)} )。

注意要显式调用 bind(this) 将事件函数上下文绑定要组件实例上,这也是 React 推崇的原则:尽量使用显式的容易理解的js代码

2.合成事件和原生事件

React 实现了一个“合成事件”层,这个事件模型保证了和 W3C 标准保持一致,“合成事件”提供了额外的好处:事件委托。

“合成事件”会以事件委托的方式绑定到组件最上层,并且在组件卸载(unmount)的时候自动销毁绑定的事件。

原生事件:比如在 componentDidMount 方法里面通过 addEventListener 绑定的事件就是浏览器原生事件。

所有通过 JSX 方式绑定的事件都是绑定到“合成事件”,建议都使用 React 的方式处理事件。

3.给事件处理函数传递参数

方法:bind(this, arg1, arg2, …)

例:

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

(5)DOM 操作

大部分情况下不需要通过查询 DOM 元素去更新组件的 UI,只要关注设置组件的状态(setState)。可能在某些情况下确实需要直接操作 DOM。

ReactDOM.render 组件返回的是对组件的引用,也就是组件实例(对于无状态状态组件来说返回 null),注意 JSX 返回的不是组件实例,它只是一个 ReactElement 对象。

例:

// A ReactElement
const myComponent = <MyComponent />

// render
const myComponentInstance = ReactDOM.render(myComponent, mountNode);
myComponentInstance.doSomething();

findDOMNode()

当组件加载到页面上之后(mounted),都可以通过 react-dom 提供的 findDOMNode() 方法拿到组件对应的 DOM 元素。

import { findDOMNode } from 'react-dom';

// Inside Component class
componentDidMound() {
  const el = findDOMNode(this);
}

注意:findDOMNode() 不能用在无状态组件上。

Refs

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

例:

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

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

如果 ref 是设置在原生 HTML 元素上,它拿到的就是 DOM 元素,如果设置在自定义组件上,它拿到的就是组件实例,这时候就需要通过 findDOMNode 来拿到组件的 DOM 元素。

因为无状态组件没有实例,所以ref 不能设置在无状态组件上,如果想要拿无状态组件的 DOM 元素的时候,就需要用一个状态组件封装一层,然后通过 ref 和 findDOMNode 去获取。

可以使用 ref 到的组件定义的任何公共方法,比如 this.refs.myTypeahead.reset()
Refs 是访问到组件内部 DOM 节点唯一可靠的方法
Refs 会自动销毁对子组件的引用(当子组件删除时)

refs注意:
不要在 render 或者 render 之前访问 refs
不要滥用 refs,比如只是用它来按照传统的方式操作界面 UI:找到 DOM -> 更新 DOM

(6)组件间通信

未完待续

(7)Mixins

未完待续

(8)Redux

可以参考我关于Redux的总结,后续还会不断进行完善:
http://www.atatech.org/articles/58588

React相关参考资料:

React中文网:
http://reactjs.cn/

React中文社区:
http://react-china.org/

React/React Native 的ES5 ES6写法对照表:
http://bbs.reactnative.cn/topic/15/react-react-native-%E7%9A%84es5-es6%E5%86%99%E6%B3%95%E5%AF%B9%E7%85%A7%E8%A1%A8

 类似资料: