首页 > 技术文章 > React重点概要

zhaoxinmei-123 2018-04-24 12:22 原文

JSX语法:

1.ReactDOM.render:用于将模板转换为HTML语言,并插入指定的DOM节点;

 语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析,HTML 语言直接写在 JavaScript 语言之中,不加任何引号

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

 

2. 它允许 HTML 与 JavaScript 的混写

    语法规则:遇到代码块(以 { 开头),就用 JavaScript 规则解析

    var names = ['Alice', 'Emily', 'Kate'];

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

结果为:hello Alice   hello Emily hello Kate

 

3.直接在模板插入 JavaScript 变量,如果这个变量是一个数组,则会展开这个数组的所有成员

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

 


 

二、组件:React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件 

    

1.React.createClass用于生成一个组件类所有组件类都必须有自己的 render 方法,用于输出组件

语法规则:

       1)组件类的第一个字母必须大写,否则会报错:如HelloMessage写成helloMessage就会报错(例1)  

      2)组件类只能包含一个顶层标签(例2)

例1:

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

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

变量 HelloMessage 就是一个组件类,<HelloMessage /> 会自动生成 HelloMessage 的一个实例 

例2:   

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

 这种写法就会报错:因为有两个顶层标签h1和p

 

3.给组件添加自定义属性:

语法规则:

  1)为组件HelloMessage添加一个name属性

  2)在组件类中使用this.props对象获取属性值

  3)因为class和for是js的保留字,所以  clss需要写成:className,for需要写成:htmlFor

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

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

 

三、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来读取NodeList组件的两个子节点span

注意1:this.props.children有三种可能值:

  1)没有子节点时:undefined

  2) 一个子节点时:Object

  3) 多个子节点时:Array

注意2:可以使用React.Children.map来遍历子节点(更多方法官方文档

 

四、PropTypes属性:就是用来验证组件实例的属性是否符合要求

注:组件的属性可以接受任意值,字符串、对象、函数等等都可以

 

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

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

 

 PropTypes 告诉 React,这个 title 属性是必须的,而且它的值必须是字符串。现在,我们设置 title 属性的值是一个数值就会报错。更多的PropTypes设置看官网

 

五、getDefaultProps方法:可以用来设置组件属性的默认方法

var MyTitle = React.createClass({
  getDefaultProps : function () {
    return {
      title : 'Hello World'
    };
  },

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

ReactDOM.render(
  <MyTitle />,
  document.body
);
结果:Hello World

 

六、获取真实的DOM节点:

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

但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性。

 

    var MyComponent = React.createClass({
      handleClick: function() {
        this.refs.myTextInput.focus();
      },
      render: function() {
        return (
          <div>
            <input type="text" ref="myTextInput" />
            <input type="button" value="Focus the text input" onClick={this.handleClick} />
          </div>
        );
      }
    });

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

上面代码中,组件 MyComponent 的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。

需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click 事件的回调函数,确保了只有等到真实 DOM 发生 Click 事件之后,才会读取 this.refs.[refName] 属性。

React 组件支持很多事件,除了 Click 事件以外,还有 KeyDownCopyScroll

 

七、this.state:将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI

    var LikeButton = React.createClass({
      getInitialState: function() {
        return {liked: false};
      },
      handleClick: function(event) {
        this.setState({liked: !this.state.liked});
      },
      render: function() {
        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')
    );

getInitialState:方法用于定义初始状态,也就是一个对象。

this.state:读取getInitialState返回的状态值  如:liked:false。

this.setState:修改状态值,每次修改以后自动调用this.render方法,在此渲染组件。

this.pros和this.setState的区别:

   1)this.props:用于一旦定义就不再改变的特性;

   2)this.setState:随着用户互动而产生变化的特性

 

九、表单:用户再表单输入的内容,属于用户跟组件互动,所以不能用this.props读取

 

    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);

 

 onChange:事件的回调函数

event.target.value:读取用户输入的值

注:像textarea、select、redio都属于这种情况

 

十:组件的声明周期:

1.组件的生命周期分为三个状态:

  Mounting:以插入真实DOM

  Updating:正在被重新渲染

  Unmounting:已移除真实DOM

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

  wil:函数正在进入状态之前调用

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

3.三种状态共计五种处理函数:

  componentWillMount()

  componentDidMount()

  componentWillUpdate(object nextProps,object nextState)

  componentDidUpdate(object prevProps,object prevState)

  componentWillUnmount()

4.特殊状态:

  componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用

  shouldComponentUpdate(object nectProps,object nextState):组件判断是否重新渲染时调用

var Hello = React.createClass({
  getInitialState: function () {
    return {
      opacity: 1.0
    };
  },

  componentDidMount: function () {
    this.timer = setInterval(function () {
      var opacity = this.state.opacity;
      opacity -= .05;
      if (opacity < 0.1) {
        opacity = 1.0;
      }
      this.setState({
        opacity: opacity
      });
    }.bind(this), 100);
  },

  render: function () {
    return (
      <div style={{opacity: this.state.opacity}}>
        Hello {this.props.name}
      </div>
    );
  }
});

ReactDOM.render(
  <Hello name="world"/>,
  document.body
);

 注意:1)style的格式:style={{opacity: this.state.opacity}}

    2) 注意setinterval()方法中,回调函数一定要加.bind(this)方法,原因是:在setInterval()中定义的回调函数,是在同步代码执行完后,随着事件触发来异步执行的,此时函数的上下文Context已经由定义该函数的Script文件变为全局变量,如果不通过bind(this)来指定由组件实例作为上下文的话,回调函数中的this会指向全局变量中的Window变量,显然不是我们想要的结果。

 

十一、Ajax

组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI

 

    var UserGist = React.createClass({
      getInitialState: function() {
        return {
          username: '',
          lastGistUrl: ''
        };
      },

      componentDidMount: function() {
        $.get(this.props.source, function(result) {
          var lastGist = result[0];
          if (this.isMounted()) {
            this.setState({
              username: lastGist.owner.login,
              lastGistUrl: lastGist.html_url
            });
          }
        }.bind(this));
      },

      render: function() {
        return (
          <div>
            {this.state.username}'s last gist is
            <a href={this.state.lastGistUrl}>here</a>.
          </div>
        );
      }
    });

    ReactDOM.render(
      <UserGist source="https://api.github.com/users/octocat/gists" />,
      document.body
    );

 我们甚至可以把一个Promise对象传入组件

    var RepoList = React.createClass({
      getInitialState: function() {
        return { loading: true, error: null, data: null};
      },

      componentDidMount() {
        this.props.promise.then(
          value => this.setState({loading: false, data: value}),
          error => this.setState({loading: false, error: error}));
      },

      render: function() {
        if (this.state.loading) {
          return <span>Loading...</span>;
        }
        else if (this.state.error !== null) {
          return <span>Error: {this.state.error.message}</span>;
        }
        else {
          var repos = this.state.data.items;
          var repoList = repos.map(function (repo) {
            return (
              <li>
                <a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br/> {repo.description}
              </li>
            );
          });
          return (
            <main>
              <h1>Most Popular JavaScript Projects in Github</h1>
              <ol>{repoList}</ol>
            </main>
          );
        }
      }
    });


ReactDOM.render(
  <RepoList
    promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')}
  />,
  document.body
);

 如果Promise对象正在抓取数据(pending状态),组件显示"正在加载";如果Promise对象报错(rejected状态),组件显示报错信息;如果Promise对象抓取数据成功(fulfilled状态),组件显示获取的数据

 

推荐阅读