reactjs首页投稿(暂停使用,暂停投稿)程序员

Reactjs 踏坑指南2: JSX&&组件

2016-07-08  本文已影响1393人  艾伦先生

JSX 知识准备

JSX 并不是一门全新的语言,仅仅是一个语法糖,允许开发者在javascript中编写XML语言。这样使用JavaScript来构建组件以及组件之间关系的应用,在代码层面显得更加清晰,而不再是使用JavaScript操作DOM来创建组件以及组件之间的嵌套关系。

作为是React的核心部分,JSX使用XML标记的方式直接声明页面。在JavaScript代码里直接写XML的语法,每一个XML标签都会被JSX转换工具转换成纯JavaScript代码。HTML直接写到JavaScript中不加任何分号,这就是JSX的语法奥义

JSX环境准备

JSX必须借助ReactJS环境才能运行。在编写JSX代码之前,需要先加载ReactJS文件,比react.js.光有ReactJs还不行,还需要加载JSX解析器。下面大家一起准备好一个最基础的ReactJS环境

这样环境就搭建好了,然后按照惯例,双手奉上一个Hello World 程序。

  <body>
    <div id="example"></div>
    <script type="text/babel">
      var HelloComponent = React.createClass({
        render: function(){
          return <span>Hello World !</span>
        }
      });
      
      ReactDOM.render(
        <HelloComponent />,
        document.getElementById('example')
      );
    </script>
  </body>

运行结果

如上面代码,我们在JavaScript中书写HTML标签时,不再像以前那样作为字符串用引号引起来,而是想在XML文件中书写一样,直接写即可。

除了<span>Hello World !</span>这种直接使用的HTML标签外,还有一个<HelloComponent />标签。这个是ReactJS创建的组件类标签,通过这种方式,把创建的HelloComponent组件引用进来。ReactJS约定,自定义的组件标签首字母一定要大些,用来区分是组件标签还是HTML标签。

注意几点

JSX执行JavaScript表达式

JSX使用{}来执行JavaScript表达式。

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

JSX定义属性&&样式使用

HTML中可以通过标签上的属性来改变当前元素的样式,当然,这在JSX中也是可以的,只不过JSX在使用行内样式的时候是有缺陷的。。使用{{}}而不是引号的方式,如下

React.render(
    <div style={{color:'red',marginTop:'20px'}}>
        xxxxx
    </div>,
    document.body
);

注:直接在标签上使用style属性时,要写成style={{}}是两个大括号,外层大括号是告知jsx这里是js语法,和真实DOM不同的是,属性值不能是字符串而必须为对象,需要注意的是属性名同样需要驼峰命名法。即margin-top要写成marginTop,属性之间以逗号间隔。还有class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。

JSX中的延展属性

在JSX中我们可以使用ES6中的最新语法...来遍历对象

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

  var Lucy = {
    name: "feng",
    votes: "23"
  }

  ReactDOM.render(
  <HelloMessage {...Lucy} />,
    document.getElementById('example')
  );

JSX中的事件绑定

JSX支持事件的绑定,语法类似于HTML中事件的绑定,不同的是这里事件的名称必须按照驼峰式,下面给个例子大家参考一下。

var HelloComponent = React.createClass({
    testClick: function (str) {
      alert('hello ' +  str)
    },
    render: function() {
      return (
          <p
          onClick={this.testClick.bind(this, 'feng')} style={{olor:'#ff6600',width:'200px', height:'100p'}}
          >
          Click me
          </p>
          )
        
    }
  })

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

知晓了JSX的基本使用之后,开始介绍ReactJS的组件的概念和使用方法

组件初步

ReactJS的基础就是实例化,即按功能封装成一个又一个的组件,各个组件维护自己的状态和UI,当状态改变时,会自动重新渲染整个组件,多个组件一起协作构成了整个ReactJS应用。

以一个简单的Hello World开始

<head>
    <meta charset="UTF-8" />
    <title>Hello React!</title>
    <script src="http://cdn.bootcss.com/react/15.2.0/react.js"></script>
    <script src="http://cdn.bootcss.com/react/15.2.0/react-dom.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
<head>
<body>
    <div id="example"></div>
    <script type="text/babel">
          var HelloMessage = React.createClass({
            render: function() {
                  return <div>Hello,{this.props.name}</div>
            }
          })
          ReactDOM.render(<HelloMessage name="World" />, document.getElementById('example'))
    </script>
</body>

运行结果:

运行结果

审查元素发现DOM结构如下:

上面的代码中,我们调用React提供的工厂方法来创建组件,其中:

这里我们需要保证render函数是纯函数:即同样的输入始终返回相同的输出,并且执行过程中没有副作用(和DOM交互或者发Ajax请求)。但一个组件要和DOM交互或者发Ajax请求需求是很正常的,那么就要用到其他生命周期方法了。

组件的状态与属性

组件本质上是状态机,输入确定,输出一定确定。组件把状态与结果一一对应起来,组件中有state与prop(状态与属性)。

props属性的用法

props是一个对象,是组建用来接收外面传来的参数,组件内部是不允许修改自己的props属性的,只能够通过父组件来修改。具体的使用方法如下

state属性的用法

React把组件当成状态机,一旦用户交互导致状态发生变化,就会触发重新渲染UI。this.state会随着用户的交互而发生变化。

组件的生命周期

生命周期各阶段

在整个ReactJS的声明周期中,主要会经历这四个阶段:创建阶段、实例化阶段、更新阶段、销毁阶段。下面通过一段代码,来深入了解组件各个环节的运作流程

  var OneComponent = React.createClass({
    //1.创建阶段
    getDefaultProps: function() {
      //在创建类的时候被调用
      console.log('getDefaultProps');
      return {}
    },

    //2.实例化阶段
    getInitialState: function() {
      //获取this.state的默认值
      console.log('getInitialState');
      return {};
    },
    componentWillMount: function() {
      //在render之前调用此方法
      //业务逻辑的处理都应该放在这里,比如对state的操作等
      console.log('componentWillMount')
    },
    render: function() {
      //渲染并返回一个虚拟DOM
      console.log('render');
      return (
          <div> hello <b> {this.props.name} </b></div>
        )
    },
    componentDidMount: function() {
      //该方法发生在render方法之后
      //在该方法中,ReactJS会使用render方法返回的虚拟DOM对象来创建真实DOM结构
      console.log('componentDidMount');
    },

    //3.个更新阶段
    componentWillReceieveProps: function() {
      //该方法发生在this.props被修改或富组件调用setProps()方法之后
      console.log('componentWillRecieveProps');
    },
    shouldComponentUpdate: function() {
      //是否需要更新
      console.log('shouldComponentUpdate');
      return true;
    },
    componentWillUpadate: function() {
      //将要更新
      console.log('componentWillUpadate');
    },
    componentDidUpdate: function() {
      //更新完毕
      console.log('componentDidUpdate');
    },
    //4.销毁阶段
    componentWillUnmout: function() {
      //销毁时被调用
      console.log('componentWillUnmout');
    }
  })

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

创建阶段:

该阶段主要发生在创建组件类的时候,即在调用React.createClass的时候。这个阶段只会触发一个getDefaultProps方法,该方法会返回一个对象,并缓存下来。然后与富组件制定的props对象合并,最后赋值给this.props作为该组件的默认属性。

实例化阶段

该阶段主要发生在实例化组件类的时候,也就是组件类被调用的时候。

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

该组件被调用的时候,这个阶段会触发一系列的流程,具体的执行顺序如下所示。

更新阶段

主要发生在用户操作或者组件有更新的时候,此时会根据用户的操作行为进行相应的页面结构的调整。该阶段也会触发一系列的流程,具体的执行顺序如下所示。

销毁阶段

注意:

绝对不要在componentWillUpdate和componentDidUpdate中调用this.setState方法,否则将导致无限循环调用。

componentWillMount、componentDidMount和componentWillUpdate、componentDidUpdate可以对应起来。区别在于,前者只有在挂载的时候会被调用;而后者在以后的每次更新渲染之后都会被调用。

组件生命周期流程图

图片来自网络文章

组件之间的通信

先创建一个父类组件Parent,它内部调用一个叫做Child的子组件,并将接收到的外部参数name传递给子组件Child。

var Parent = React.createClass({
    handleClick: function() {
      this.refs.myTextInput.focus();
    },
    render: function() {
      return (
          <div onClick={this.handleClick}>
            <input type="text" ref="myTextInput" />
            Parent is:
              <Child name={this.props.name}></Child>
          </div>
        )
    }
});

在创建一个子类组件Child

  var Child = React.createClass({
    render: function() {
      return <span>{this.props.name}</span>
    }
  });

自后通过React.render方法将组件渲染到页面上

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

运行结果

整个应用的功能是父组件接收传入的用户名称,并将用于名称传给子组件,最后再由子组件渲染显示到页面上。这些组件直接按是怎么通讯的呢?下面通过两方面介绍一下

组件实践

1. 静态组件

var MyComponent=React.createClass({
  render: function() {
   return <h1 className="my-h1" style={{color:'red'}}>Hello world!</h1>;
 }
});
ReactDOM.render(
 <MyComponent />,
 document.getElementById('example')
);

运行结果

运行结果

2. 动态组件

var Counter = React.createClass({
    incrementCount: function(){
        this.setState({
            count: this.state.count + 1
        });
    },
    getInitialState: function(){
        return {
            count: 0
        }
    },
    render: function(){
        return (
            <div className="my-component">
                <h1>Count: {this.state.count}</h1>
                <button type="button" onClick={this.incrementCount}>{this.props.name}</button>
            </div>
        );
    }
});

ReactDOM.render(
    <Counter name="递增按钮" />,
    document.getElementById('mount-point')
);

运行结果:

递增按钮

参考内容

上一篇下一篇

猜你喜欢

热点阅读