React 核心思想之聲明式渲染

React 發展很快,概念也多,本文目的在於幫助初學者理清 React 核心概念。javascript

React 及 React 生態html

React 的核心概念只有 2 點:前端

  • 聲明式渲染(Declarative)java

  • 基於組件(Component-Based)react

聲明式渲染

聲明式與命令式

  • 命令式編程:命令「機器」如何去作事情(how),這樣無論你想要的是什麼(what),它都會按照你的命令實現。webpack

  • 聲明式編程:告訴「機器」你想要的是什麼(what),讓機器想出如何去作(how)。git

舉例:github

// 命令式關注如何作(how)

var numbers = [1,2,3,4,5]

var doubled = []

for(var i = 0; i < numbers.length; i++) {

  var newNumber = numbers[i] * 2
  doubled.push(newNumber)

}
console.log(doubled) //=> [2,4,6,8,10]

遍歷整個數組,取出每一個元素,乘以二,而後把翻倍後的值放入新數組,每次都要操做這個雙倍數組,直到計算完全部元素。web

// 聲明式關注作什麼(what)

var numbers = [1,2,3,4,5]

var doubled = numbers.map(function(n) {

  return n * 2
})
console.log(doubled) //=> [2,4,6,8,10]

map 函數所做的事情是將直接遍歷整個數組的過程概括抽離出來,讓咱們專一於描述咱們想要的是什麼(what)。算法

模板渲染

渲染:模板 => HTML => 頁面視圖

發生在服務器的叫後端模板渲染,公司用的是velocity

發生在客戶端的叫前端模板渲染,經常使用的有 artTemplate

artTemplate 爲例。

  • 模板

<script id="test" type="text/html">
    <div>
        <h2>北京時間: {{ date.toLocaleTimeString() }}.</h2>
    </div>
</script>
  • 數據

  • 渲染

setInterval(function() {
    // 數據
    var data = {
        date: new Date()
    };
    // 渲染(將數據和模板綁定在)
    var html = template('test', data);
    // 渲染
    document.getElementById('container').innerHTML = html;
},100)

React 聲明式渲染

和普通模板不一樣的是,React 模板寫在 JS 文件中,而不是 html 的 <script> 標籤中。能使用全部 JS 語法,而不僅有模板語法,因此更加靈活。

function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

// 數據
const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

// 模板
const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);

// 渲染
ReactDOM.render(
  element,
  document.getElementById('root')
);

React 可局部渲染,且只渲染改變了的數據。純模板只能總體渲染。

高效的局部渲染意味着,開發者 只須要維護可變的數據 state (what) ,讓 react 框架幫助咱們處理 DOM 操做(what)。

// React.createClass 建立模板容器(類)
class Clock extends Component {
  render() {
      return (
          <div>
              <h2>北京時間: { this.props.date.toLocaleTimeString() }</h2>
          </div>
      );
  }
}

setInterval(function() {
    // ReactDOM.render 渲染指令
    ReactDOM.render(
      // date 數據
      <Clock date={new Date()} />,
      document.getElementById('container')
    );
}, 100);

state 只用於存放可變的數據。

經過 setState 告訴 react 什麼數據變了,React 會自動更新數據改變部分的視圖

class Clock extends Component {
  // 初始化
  constructor(props) {
    super(props);
    // state 只用於存放可變的狀態
    this.state = {date: new Date()};
  }
  // 初始化完成後執行
  componentDidMount() {
    setInterval(() => {
      // setState 在修改 state 參數後會自動調用 render 方法。
      this.setState({
        date: new Date()
      })
    },100)
  }

  render() {
      return <h2>北京時間: { this.state.date.toLocaleTimeString() }</h2>
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('js-main')
);

React 經過 diffing 算法計算如何更新視圖。而 diffing 算法有個 的假設前提,開發人員會提供給長列表的每一個子項一個 ID,幫助算法進行對比。

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

完成的渲染流程

初始化的渲染流程分爲 3 步。

第一步,開發者使用 JSX 語法寫 React,babel 會將 JSX 編譯爲瀏覽器能識別的 React JS 語法。這一步,通常配合 webpack 在本地進行。

第二步,執行 ReactDOM.render 函數,渲染出虛擬DOM。

第三步,react 將虛擬DOM,渲染成真實的DOM。

頁面更新的流程一樣也是 3 步。

第一步,當頁面須要更新時,經過聲明式的方法,調用 setState 告訴 react。

第二步,react 自動調用組件的 render 方法,渲染出虛擬 DOM。

第三步,react 會經過 diffing 算法,對比當前虛擬 DOM 和須要更新的虛擬 DOM 有什麼區別。而後從新渲染區別部分的真實 DOM。

相關文章
相關標籤/搜索