前端之React實戰-交互與動態UI

jopen 9年前發布 | 27K 次閱讀 React JavaScript開發

Interactivity and Dynamic UIs

React.findDOMNode()

組件并不是真實的 DOM 節點,而是存在于內存之中的一種數據結構,叫做虛擬 DOM (virtual DOM)。只有當它插入文檔以后,才會變成真實的 DOM 。根據 React 的設計,所有的 DOM 變動,都先在虛擬 DOM上發生,然后再將實際發生變動的部分,反映在真實 DOM上,這種算法叫做 DOM diff ,它可以極大提高網頁的性能表現。但是,有時需要從組件獲取真實 DOM 的節點,這時就要用到 React.findDOMNode 方法。

var MyComponent = React.createClass({
  handleClick: function() {
    React.findDOMNode(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>
    );
  }
});

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

需要注意的是,由于 React.findDOMNode 方法獲取的是真實 DOM ,所以必須等到虛擬 DOM 插入文檔以后,才能使用這個方法,否則會返回 null 。上面代碼中,通過為組件指定 Click 事件的回調函數,確保了只有等到真實 DOM 發生 Click 事件之后,才會調用 React.findDOMNode 方法。

getInitialState

設置State的初始狀態。

var MyComponent = React.createClass({
    getInitialState: function(){
        return {
            count: 5
        }
    },
    render: function(){
        return (
            <h1>{this.state.count}</h1>
        )
    }
});

Style

參考資料

  • React行內樣式最佳實踐

Inline-style

在React中,如果要使用行內元素,不可以直接使用style="”這種方式,可以有:
import React from 'react';

var style = {
  backgroundColor: '#EEE'
};

export default React.createClass({
  render: function () {
    return (
      <div style={style}>
      //或者<div style={{backgroundColor: '#EEE'}}>
        <h1>Hello world</h1>
      </div>
    )
  }
});
可以看出,React的style屬性接收的也是一個JavaScript對象。

Class

你可以根據這個策略為每個組件創建 CSS 文件,可以讓組件名和 CSS 中的 class 使用一個命名空間,來避免一個組件中的一些 class 干擾到另外一些組件的 class。

app/components/MyComponent.css

.MyComponent-wrapper {
  background-color: #EEE;
}

app/components/MyComponent.jsx

import './MyComponent.css';
import React from 'react';

export default React.createClass({
  render: function () {
    return (
      <div className="MyComponent-wrapper">
        <h1>Hello world</h1>
      </div>
    )
  }
});

Multiple Class

上文中提及的利用className方式賦值,如果在存在多個類名的情況下:
render: function() {
  var cx = React.addons.classSet;
  var classes = cx({
    'message': true,
    'message-important': this.props.isImportant,
    'message-read': this.props.isRead
  });
  // same final string, but much cleaner
  return <div className={classes}>Great, I'll be there.</div>;
}

Event

React對于事件的支持非常完善,可以查看[這里][8]。React 實現了一個“合成事件”層(synthetic event system),這個事件模型保證了和 W3C 標準保持一致,所以不用擔心有什么詭異的用法,并且這個事件層消除了 IE 與 W3C 標準實現之間的兼容問題。“合成事件”額外提供了兩個好處:**自動綁定上下文和事件委托**
  • “合成事件”自動將事處理件方法的上下文綁到當前組件,所以handleClick方法里面可以直接使用this.setState。

  • “合成事件”會以事件委托(event delegation)的方式綁定到組件最上層,并且在組件卸載(unmount)的時候自動銷毀綁定的事件。

    當然,在React中,也可以使用原生事件,比如你在 `componentDidMount` 方法里面通過 `addEventListener` 綁定的事件就是瀏覽器原生事件。使用原生事件的時候注意在 `componentWillUnmount` 解除綁定 `removeEventListener`。所有通過 JSX 這種方式綁定的事件都是綁定到“合成事件”,除非你有特別的理由,建議總是用 React 的方式處理事件。

Event Bind

最基本的綁定方式就是依靠類似于```onClick={handleClick}```的方式,要注意,這里不同于ng-click,onClick傳遞的參數只能是一個方法,而不能是一個調用。如果要簡單來寫的話可以采Lambda表達式的方式:
onClick={()=>{alert(1);}}

Event Params

給事件處理函數傳遞額外參數的方式:`bind(this, arg1, arg2, ...)`
render: function() {
    return <p onClick={this.handleClick.bind(this, 'extra param')}>;
},
handleClick: function(param, event) {
    // handle click
}
由上面可以看出,Event一般都是作為最后一個參數傳遞到handleClick中,這里的event是SyntheticEvent對象,它的主要屬性如下:
boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
void isDefaultPrevented()
void stopPropagation()
void isPropagationStopped()
DOMEventTarget target
number timeStamp
string type

List Element

在React中,也會經常遇到需要為某個群組綁定事件的情況,可以參考如下代碼:
var GroceryList = React.createClass({
  handleClick: function(i) {
    console.log('You clicked: ' + this.props.items[i]);
  },
  render: function() {
    return (
      <div>
        {this.props.items.map(function(item, i) {
          return (
            <div onClick={this.handleClick.bind(this, i)} key={i}>{item}</div>
          );
        }, this)}
      </div>
    );
  }
});
React.render(
  <GroceryList items={['Apple', 'Banana', 'Cranberry']} />, mountNode
);

TouchEvent

If you'd like to use React on a touch device such as a phone or tablet, simply callReact.initializeTouchEvents(true);to enable touch event handling.

接口暴露

譬如在某個子組件中,提供了某個方法:

var ButtonComponent = React.createClass({
    getDragonKillingSword: function(){
        //送寶刀
    },
    render: function(){
        return (<button onClick={this.getDragonKillingSword}>屠龍寶刀,點擊就送</button>);
    }
});

如果在父組件中想手動調用該方法,則可以利用ref方式:

var ImDaddyComponent = React.createClass({
  render: function(){
    return (
      <div>
        //其他組件
        <ButtonComponent />
        //其他組件
      </div>
    );
  }
});

在父組件的功能方程中:

this.refs.getSwordButton.getDragonKillingSword();

反之,如果需要在子組件中調用父組件的方法,則可以直接將父組件的方法作為Props參數傳入到子組件中:

<ButtonComponent clickCallback={this.getSwordButtonClickCallback}/>

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

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

不過筆者習慣還是將整個獲取數據,處理數據的業務邏輯放在Angular中進行。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!