menu

React组件思想

  • date_range 06/09/2019 03:25 info
    sort
    笔记
    label
    React
组件:

添加组件属性需要注意,class属性需要写成className,for属性需要写成htmlFor,这是因为classfor是JavaScript的保留字。

this.props.children

this.props对象的属性与组件的属性一一对应,但是有一个例外,就是this.props.children属性。它表示组件的所有子节点。

<body>
  <div id="red">
    <script type="text/babel">
    class Message extends React.Component{
      render(){
        return(
                <ol>
                  {
                    React.Children.map(this.props.children,function (child) {
                      return <li>{child}</li>
                    })
                  }
                </ol>
        )
      }
    }
    ReactDOM.render(
            <Message>
              <span>我韩浩</span>
              <span>会很好的</span>
            </Message>,
            document.getElementById('red')
    );
    </script>

  </div>
  </body>
  • 需要注意:this.props.children的值有三种可能:如果当前组件没有子节点,它就是undefined;如果有一个子节点,数据类型是object;如果有多个子节点,数据类型就是array.所以,处理this.props.children的时候要小心。
  • React提供一个工具方法React.Children来处理this.props.children。我们可以用React.Children.map来遍历子节点,而不用担心this.props.children的数据类型是undefined还是object.
PropTypes

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

组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求。

<body>
  <div id="red">
    <script type="text/babel">
    var data = "你知道,我很喜欢你吗?";
    class Message extends React.Component{
      static good = {
        title:PropTypes.string.isRequired,
      };
      render(){
        return <h3>{this.props.title}</h3>
      }
    }
    ReactDOM.render(
            <Message title={data}/>,
            document.getElementById('red')
    )
    </script>
  </div>
  </body>
获取真实的DOM节点

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

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

<body>
  <div id="red">
    <script type="text/babel">
      class MyTextInput extends React.Component{
        constructor(props){
          super(props);
          this.myTextInput = React.createRef();
          this.handleClick = this.handleClick.bind(this)
        }
        handleClick(){
          this.myTextInput.current.focus();
        }
        render(){
          return(
                  <div>
                    <input type="text" ref={this.myTextInput}/>
                    <input type="button" value="input" onClick={this.handleClick}/>
                  </div>
          )
        }
      }
    ReactDOM.render(
            <MyTextInput/>,
    document.getElementById('red')
    )
    </script>
  </div>
  </body>
this.state

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

 <body>
  <div id="red">
    <script type="text/babel">
    class LikeMessage extends React.Component{
     constructor(props){
       super(props);
       this.state = {
         liked:false
       }
       this.handClick = this.handClick.bind(this)
     }
     handClick(){
       this.setState({liked:!this.state.liked})
     }
     render(){
       var text = this.state.liked? '喜欢':'讨厌';
       return(
               <p onClick={this.handClick}>我{text}你</p>
       )
     }
    }
    ReactDOM.render(
            <LikeMessage/>,
            document.getElementById('red')
    )
    </script>
  </div>
  </body>
表单

用户在表单填入的内容,属于用户跟组件的互动,所以不能用this.props读取。

<body>
  <div id="red">
    <script type="text/babel">
    class Input extends React.Component{
     constructor(props){
       super(props);
       this.state = {
         value:'Hello'
       }
       this.handleChange = this.handleChange.bind(this)
     }
     handleChange(event){
       this.setState({value:event.target.value});
     }
     render(){
       var value = this.state.value;
       return(
         <div>
           <input type="text" value={value} onChange={this.handleChange}/>
           <p>{value}</p>
         </div>
       )
     }
    }
    ReactDOM.render(
            <Input/>,
            document.getElementById('red')
    )
    </script>
  </div>
  </body>

上面代码中,文本输入框的值,不能用this.props.value读取,而要定义一个onChange事件的回调函数,通过event.target.value读取用户输入的值。

textarea元素、select元素、radio元素都属于这种情况。

组价的生命周期

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

Mounting:已插入真实DOM

Updating:正在被重新渲染

Unmounting:已移出真实DOM

React为每个状态都提供了两种处理函数,will函数在进入状态之前调用,did函数在进入状态之后调用,三种状态共计五种处理函数。

componentWillMount()

componentDidMount()

componentWillUpdate(object nextProps, object nextState)

componentDidUpdate(object prevProps, object prevState)

componentWillUnmount()

此外,React还提供两种特殊状态的处理函数。

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

shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
<body>
  <div id="red">
    <script type="text/babel">
    class Hello extends React.Component{
      constructor(props){
        super(props);
        this.state = {
          opacity:1.0
        };
      }
      componentDidMount(){
        this.timer = setInterval(function () {
          var opacity = this.state.opacity;
          opacity -= 0.05;
          if(opacity < 0.1){
            opacity = 1.0
          }
          this.setState({
            opacity:opacity
          });
        }.bind(this),100);
      }
      render(){
        return(
                <div style=>
                  我很好,{this.props.name}
                </div>
        )
      }
    }
    ReactDOM.render(
            <Hello name="你要好好的"/>,
            document.getElementById('red')
    )
    </script>
  </div>
  </body>
Ajax

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

<body>
  <div id="red">
   <script type="text/babel">
     class UserGist extends React.Component{
       constructor(props){
         super(props);
         this.state = {
           username:'',
           lastGistUrl:''
         }
       }
       componentDidMount(){
         $.get(this.props.source,function (result) {
           var lastGist = result[0];
           this.setState({
             username:lastGist.owner.login,
             lastGistUrl:lastGist.html_url
           });
         }.bind(this));
       }
       render(){
         return (
                 <div>
                   {this.state.username}'s 就是这个<a href={this.state.lastGistUrl}>here</a>
                 </div>
         )
       }
     }
     ReactDOM.render(
             <UserGist source="https://api.github.com/users/octocat/gists"/>,
             document.getElementById('red')
     )
    </script>
  </div>
  </body>

上面代码使用jQuery完成Ajax请求,这是为了便于说明。React本身没有任何依赖,完全可以不用jQuery,而使用其他库。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <script src="../build/react.development.js"></script>
    <script src="../build/react-dom.development.js"></script>
    <script src="../build/babel.min.js"></script>
    <script src="../build/prop-types.js"></script>
    <script src="../build/jquery.min.js"></script>
  </head>
  <body>
  <div id="red">
   <script type="text/babel">
     class RepoList extends React.Component{
       constructor(props) {
         super(props);
         this.state = {
           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(){
         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,index){
             return(
                     <li key={index}><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.getElementById('red')
     )
    </script>
  </div>
  </body>
</html>