React JS入门

官方网站https://facebook.github.io/react/docs/events.html#supported-events
React 是 Facebook 推出的一个用来构建用户界面的 JavaScript 库。React 的核心思想是:封装组件,各个组件维护自己的状态和 UI,当状态变更,自动重新渲染整个组件。

基于这种方式的一个直观感受就是我们不再需要不厌其烦地来回查找某个 DOM 元素,然后操作 DOM 去更改 UI。

React 大体包含下面这些概念:
组件
JSX
Virtual DOM
Data Flow

一、配置开发环境
二、React代码结构
使用 React 的网页源码,结构大致如下。

<!DOCTYPE html>
<html>
  <head>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/babel">//因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel"
      // ** Our code goes here! **
    </script>
  </body>
</html>

React 组件通过一个render()方法,接受输入的参数并返回展示的对象。输入的参数通过render()传入组件后,将存储在this.props

ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。

代码将一个 h1 标题,插入 example 节点:

<body>
    <div id="example"></div>
    <script type="text/babel">
      ReactDOM.render(
        <h1>Hello, world!</h1>,
        document.getElementById('example')
      );
    </script>
</body>

HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写

三、JSX 语法
(1)为什么要引入 JSX 这种语法?
传统的 MVC 是将模板放在其他地方,比如 <script> 标签或者模板文件,再在 JS 中通过某种手段引用模板。按照这种思路,我们面对四处分散的模板片段不知所措,React 认为组件才是王道,而组件是和模板紧密关联的,组件模板和组件逻辑分离让问题复杂化了。所以就有了 JSX 这种语法,就是为了把 HTML 模板直接嵌入到 JS 代码里面,这样就做到了模板和组件关联,但是 JS 不支持这种包含 HTML 的语法,所以需要通过工具将 JSX 编译输出成 JS 代码才能使用。

<div id="example"></div>
<script type="text/babel">
      var names = ['Alice', 'Emily', 'Kate'];

      ReactDOM.render(
        <div>
        {
          names.map(function (name) {
            return <div>Hello, {name}!</div>
          })
        }
        </div>,
        document.getElementById('example')
      );
</script>

JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。
(2)详解jsx语法:
JSX语法,像是在Javascript代码里直接写XML的语法,实质上这只是一个语法糖,每一个XML标签都会被JSX转换工具转换成纯Javascript代码,React 官方推荐使用JSX, 当然你想直接使用纯Javascript代码写也是可以的,只是使用JSX,组件的结构和组件之间的关系看上去更加清晰。

//使用JSX
React.render(
    <div>
        <div>
            <div>content</div>
        </div>
    </div>,
    document.getElementById('example')
);

//不使用JSX
React.render(
    React.createElement('div', null,
        React.createElement('div', null,
            React.createElement('div', null, 'content')
        )
    ),
    document.getElementById('example')
);

那么也就是说,我们写一个XML标签,实质上就是在调用React.createElement这个方法,并返回一个ReactElement对象。

a. JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员,例如:arr变量是一个数组,结果 JSX 会把它的所有成员,添加到模板

var arr = [
  <h1>Hello world!</h1>,
  <h2>React is awesome</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('example')
);

b. 在 JSX 里使用注释也很简单,就是沿用 JavaScript,唯一要注意的是在一个组件的子元素位置使用注释要用 {} 包起来。

var content = (
  <Nav>
      {/* child comment, put {} around */}
      <Person
        /* multi
           line
           comment */
        name={window.isLoggedIn ? window.name : ''} // end of line comment
      />
  </Nav>
);

c. 利用 JSX 编写 DOM 结构,可以用原生的 HTML 标签,也可以直接像普通标签一样引用 React 组件。这两者约定通过大小写来区分,小写的字符串是 HTML 标签,大写开头的变量是 React 组件。

使用 HTML 标签:

var myDivElement = <div className="foo" />;
React.render(myDivElement, document.body);

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

四.React 组件
React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类

(1)组件有两个核心概念:props,state
一个组件就是通过这两个属性的值在 render 方法里面生成这个组件对应的 HTML 结构。

注意:组件生成的 HTML 结构只能有一个单一的根节点。

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

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

(2)组件的创建
一个组件类必须由调用 React.createClass 创建,并且提供一个 render 方法以及其他可选的生命周期函数、组件相关的事件或方法定义。

ar HelloMessage = React.createClass({
  render: function() {
    return <h1>Hello {this.props.name}</h1>;
  }
});

ReactDOM.render(
  <HelloMessage name="John" />,
  document.getElementById('example')
);

变量 HelloMessage 就是一个组件类。模板插入 <HelloMessage /> 时,会自动生成 HelloMessage 的一个实例(下文的”组件”都指组件类的实例)。所有组件类都必须有自己的 render 方法,用于输出组件。
组件的用法与原生的 HTML 标签完全一致,可以任意加入属性,比如 <HelloMessage name="John"> ,就是 HelloMessage 组件加入一个 name 属性,值为 John。组件的属性可以在组件类的 this.props 对象上获取,比如 name 属性就可以通过 this.props.name 读取。
注意:
组件类的第一个字母必须大写,否则会报错,比如HelloMessage不能写成helloMessage。
class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。
另外,组件类只能包含一个顶层标签,否则也会报错。

(3)this.props.children 属性
this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点
NoteList 组件有两个 span 子节点,它们都可以通过 this.props.children 读取

var NotesList = React.createClass({
  render: function() {
    return (
      <ol>
      {
        React.Children.map(this.props.children, function (child) {
          return <li>{child}</li>;
        })
      }
      </ol>
    );
  }
});

ReactDOM.render(
  <NotesList>
    <span>hello</span>
    <span>world</span>
  </NotesList>,
  document.body
);
//1.hello
//2.world

this.props.children 的值有三种可能:
如果当前组件没有子节点,它就是 undefined ;
如果有一个子节点,数据类型是 object ;
如果有多个子节点,数据类型就是 array 。
所以,处理 this.props.children 的时候要小心。

React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object

(4)PropTypes属性
组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。
组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求:

<div id="example"></div>
    <script type="text/babel">

      var data = 123;

      var MyTitle = React.createClass({
        propTypes: {
          title: React.PropTypes.string.isRequired,
        },

        render: function() {
          return <h1> {this.props.title} </h1>;
        }
      });

      ReactDOM.render(
        <MyTitle title={data} />,
        document.getElementById('example')
      );

    </script>

Mytitle组件有一个title属性。PropTypes 告诉 React,这个 title 属性是必须的,而且它的值必须是字符串。当我们设置 title 属性的值是一个数值时,控制台会显示一行错误信息。

(5)getDefaultProps 方法可以用来设置组件属性的默认值。

var MyTitle = React.createClass({
  getDefaultProps : function () {
    return {
      title : 'Hello World'
    };
  },
  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});
ReactDOM.render(
  <MyTitle />,
  document.body
);

(6)组件的生命周期
getInitialState
初始化 this.state 的值,只在组件装载之前调用一次。
getDefaultProps
只在组件创建时调用一次并缓存返回的对象(即在 React.createClass 之后就会调用)。

组件的生命周期分成三个状态:

Mounting:已插入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM

React 为每个状态都提供了两种处理函数:

will 函数在进入状态之前调用
did 函数在进入状态之后调用

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

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

更新组件状态:这些方法不会在首次 render 组件的周期调用

componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)

卸载(删除)组件
componentWillUnmount
(7)组件的style属性的设置方式也值得注意,不能写成

style="opacity:{this.state.opacity};"

而要写成

style={{opacity: this.state.opacity}}

(8)this.state
组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI

<script type="text/babel">
var LikeButton = React.createClass({
  getInitialState: function() {  //getInitialState 方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取
    return {liked: false};
  },
  handleClick: function(event) {
    this.setState({liked: !this.state.liked});//当用户点击组件,导致状态变化,this.setState 方法就修改状态值
  },
  render: function() {  //每次修改以后,自动调用 this.render 方法,再次渲染组件。
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('example')
);
    </script>

五、Dom操作
组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。

大部分情况下你不需要通过查询 DOM 元素去更新组件的 UI,你只要关注设置组件的状态(setState)。但是可能在某些情况下你确实需要直接操作 DOM。比如,用于获取用户的输入,这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。
(1)getDOMNode()
当组件加载到页面上之后(mounted),你就可以通过 getDOMNode() 方法拿到组件对应的 DOM 元素。
(2)另外一种方式就是通过在要引用的 DOM 元素上面设置一个 ref 属性指定一个名称,然后通过 this.refs.name 来访问对应的 DOM 元素。

ar MyComponent = React.createClass({
  handleClick: function() {
    this.refs.myTextInput.focus();//文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。
  },
  render: function() {
    return (
      <div>
        <input type="text" ref="myTextInput" /> //MyComponent 的子节点有一个文本输入框,用于获取用户的输入,这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的
        <input type="button" value="Focus the text input" onClick={this.handleClick} />
      </div>
    );
  }
});

ReactDOM.render(
  <MyComponent />,
  document.getElementById('example')
);

需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click 事件的回调函数,确保了只有等到真实 DOM 发生 Click 事件之后,才会读取 this.refs.[refName] 属性。
React 组件支持很多事件,除了 Click 事件以外,还有 KeyDown 、Copy、Scroll 等https://facebook.github.io/react/docs/events.html#supported-events
注意:
Refs 是访问到组件内部 DOM 节点唯一可靠的方法
不要在 render 或者 render 之前访问 refs

六、表单
表单不同于其他 HTML 元素,因为它要响应用户的交互,显示不同的状态,所以在 React 里面会有点特殊。用户在表单填入的内容,属于用户跟组件的互动,所以不能用 this.props 读取。

表单元素有这么几种属于状态的属性:

value,对应 <input><textarea>
checked,对应类型为 checkbox 和 radio 的 <input>
selected,对应 <option>

表单元素包含以上任意一种状态属性都支持 onChange 事件监听状态值的更改。

var Input = React.createClass({
  getInitialState: function() {
    return {value: 'Hello!'};
  },
  handleChange: function(event) {
    this.setState({value: event.target.value});
  },
  render: function () {
    var value = this.state.value;
    return (
      <div>
        <input type="text" value={value} onChange={this.handleChange} />
        <p>{value}</p>
      </div>
    );
  }
});

ReactDOM.render(<Input/>, document.body);
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值