學習 React.js : 概念和起步

Learning React.js: Getting Started and Concepts

By Ken Wheeler (@ken_wheeler)

#簡介

今天我們開始一個新系列的學習,學習 React,我們將集中在怎麼熟練並且有效的使用臉書的 React 庫上。在我們開始實際寫程序之前,還有更重要的一步,我們先講解一些基本概念,好了,我們開始吧。

##什麼是 React?

React 是臉書開發的一個 UI 庫,可以用來方便創建具有交互性,狀態性 & 重用性的 UI 組件。它已經被運用在了臉書的生產環境上了,並且 Instagram.com 也完全是用 React 來寫的。

它的一個獨一無二的買點是,它不僅能用在客戶端,還能在服務端渲染,並且可以配合著用。

它還有一個概念叫做虛擬DOM,它會基於狀態更新選擇性的進行渲染子節點。這使得你的組件通過最少的DOM操作保持更新。

##虛擬DOM是怎樣工作的?

想象一下,你有一個人類模型。它有一個人應該有的各種屬性,並且反映了這個人當前的狀態。React 差不多就是這樣對待 DOM 的。

現在再想一下,如果你讓這個對象發生一些改變,比如說加個小鬍子,然後再加點肌肉,再加雙 Steve Buscemi 那樣的眼睛。在 React 世界,當你做了這些更新之後,有兩件事情會發生。首先, React 執行"髒值檢查",確定發生了什麼改變。然後第二步是調和,把檢測到的更新結果反映到 DOM 上。

React 的方式,不會真的去再生一個小孩出來,重新把他們養大,而只是做個臉和手臂的整形。也就是說,如果你在輸入框裏面的文字發生改變,除非輸入框的父節點發生渲染,否則文字將會保持原狀。

由於 React 用的是假的 DOM 而不是真的那個,那麽這就讓有了一種新的可能。我們可以在服務端來渲染這個假的 DOM,然後,duang~服務端的 React View。

#開始

想要開始用 React 很簡單,只要去下載他們提供的 starter kit 就好:

React Starter Kit

你也可以叉他們提供的 JSFiddle:

React JSFiddle

##頁面設置

那麽我們來設置頁面,你需要導入 react.jsJSXTransformer.js,然後用 script 開始寫你的組件,記得把這個節點的 type 設置為 text/jsx

<!-- lang: js -->
<!DOCTYPE html>
<html>
  <head>
    <script src="build/react.js"></script>
    <script src="build/JSXTransformer.js"></script>
  </head>
  <body>
    <div id="mount-point"></div>
    <script type="text/jsx">
      // React Code Goes Here
    </script>
  </body>
</html>

在 React 裏面,組件必須加載到一個元素上,所以在例子裏面,我們可以用 div mount-point 來作為它的父容器。

當然這只是一個最簡單的起點,黨你實際上要寫點什麼的時候,最好用 Browerify 或者 webpack 這樣的工具來把你的組件拆分到不同的文件中。

#基礎

React 的基本單元模塊叫做組件(component),讓我們來寫一個:

<!-- lang: js -->
<script type="text/jsx">
    /** @jsx React.DOM */
    React.renderComponent(
        <h1>Hello,world!</h1>,document.getElementById('myDiv')
    );
</script>

如果你沒看之前的代碼,那你肯定一頭霧水不知道這個 javascript/HTML 到底做了什麼。

##JSX

這就是所謂的 JSX,它是一種 Javascript XML 語法轉換,可以讓你在你的 Javascript 裏面寫 類HTML。我之所以說 類HTML 是有多重含義。你僅僅是基於一個關聯對象來寫 XML 。

對於正常的 html 標籤,在 JSX 中,class 屬性變成了 className,而 for 則變成了 htmlFor,這是因為有些 Javascript 的保留字。你可以看這裏來瞭解更多的不同。

如果你不用 JSX,那麽這裏是不用它的一個版本:

<!-- lang: js -->
/** @jsx React.DOM */
React.renderComponent(
  React.DOM.h1(null,'Hello,world!'),document.getElementById('myDiv')
);

如果你願意,你可以看這裏,來瞭解更多支持的元素。

在你的第一個代碼片段裏面,你有沒有注意到在頂行的 /** @jsx React.DOM */ ?它非常重要,它告訴 React 我們用了 JSX 所以這段代碼需要轉換,所以你用 JSX 語法的時候,你需要把它包含進來。

##組件

黨使用上面的 renderComponent 方法,第一個參數是我們希望渲染的組件,第二個參數是將要掛載上去的DOM 節點。我們可以用 createClass 方法來創建自定義組件類。它可以使用對象作為參數。下面讓我們來創建一個:

<!-- lang: js -->
var MyComponent = React.createClass({
    render: function(){
        return (
            <h1>Hello,world!</h1>
        );
    }
});

創建一個類之後,我們可以在 document 中像這樣渲染它:

<!-- lang: js -->
React.renderComponent(
    <MyComponent/>,document.getElementById('myDiv')
);

屌不屌,嗯哼?

##Props

當我們使用我們定義的組件的時候,我們可以添加屬性,叫做 props,這些屬性在我們的組件仲可以通過 this.props 調用並且可以在我們的渲染方法裏面動態渲染數據:

<!-- lang: js -->
var MyComponent = React.createClass({
    render: function(){
        return (
            <h1>Hello,{this.props.name}!</h1>
        );
    }
});

React.renderComponent(<MyComponent name="Handsome" />,document.getElementById('myDiv'));

##Specs,生命週期 & 狀態

render 方法是創建組件唯一需要進行測試的部分,不過這裏有一些生命週期相關方法和測試我們可以用到,當我們在實際的組件中應該會有所幫助。

###生命週期方法

  • componentWillMout 執行一次,在客戶端和服務端將要執行渲染的時候
  • componentDidMount 執行一次,只在客戶端,當渲染完成之後
  • shouldComponentUpdate 返回值判定組件是否需要更新的
  • componentWillUnmount 在卸載之前執行

###Specs

  • getInitialState 返回狀態初期值
  • getDefaultProps 設置退避 props 值,如果 沒有可用 props
  • mixins 一個對象數組,用來擴展當前組件的功能

###State

每個組件都有一個 state 對象和一個 props 對象。State 通過 setState 來設置。調用 setState 會觸發 UI 更新,它是 React 交互的基礎。如果我們想在所有交互開始之前設置一個初始狀態,我們可以用 getInitialState 方法。下面,讓我們看看我們是如何設置組件的狀態的:

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

##事件

React 還有一個內建跨瀏覽器事件系統。這些事件可以作為組件的屬性來追加也可以觸發方法。讓我們來通過事件來創建一個計數器:

<!-- lang: html -->
<div id="mount-point"></div>

<!-- lang: js -->
/** @jsx React.DOM */

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

React.renderComponent(<Counter/>,document.getElementById('mount-point'));

<!-- lang: css -->
body { 
  background: #bdc3c7;
  padding: 40px; 
}
.counter {
  width: 300px;
  margin: auto;
  background: #9b59b6;
  color: white;
  padding: 20px;
  text-align: center;
  h1 {
    margin: 0;
    padding: 20px;
    font-size: 36px;
  }
  button {
    background: #f1c40f;
    border: 0;
    box-shadow: 0px 5px 0px darken(#f1c40f,20%);
    padding: 20px;
    width: 100%;
    outline: none;
    border-radius: 3px;
    color: darken(#8e44ad,10%);
    font-weight: bold;
  }
}

##單向數據流

在 React 中,英勇的數據通過 state 和 props 對象單向傳播,和其他的雙向綁定的庫完全不一樣,比如說 Angular。意思也就是說,在多組件模式下,一個共通父組件將負責管理狀態以及將它通過 props 向下傳播。

如果需要,你的狀態可以通過使用 setState 方法來更新,以確保 UI 的刷新被執行。結果值會被傳播到子組件,通過使用屬性。也就是說子組件可以用 this.props 來訪問的那些。

下面用一個例子來解釋這些概念:

<!-- lang: js -->
/** @jsx React.DOM */
var FilteredList = React.createClass({
  filterList: function(event){
    var updatedList = this.state.initialItems;
    updatedList = updatedList.filter(function(item){
      return item.toLowerCase().search(
        event.target.value.toLowerCase()) !== -1;
    });
    this.setState({items: updatedList});
  },getInitialState: function(){
     return {
       initialItems: [
         "Apples","Broccoli","Chicken","Duck","Eggs","Fish","Granola","Hash Browns"
       ],items: []
     }
  },componentWillMount: function(){
    this.setState({items: this.state.initialItems})
  },render: function(){
    return (
      <div className="filter-list">
        <input type="text" placeholder="Search" onChange={this.filterList}/>
      <List items={this.state.items}/>
      </div>
    );
  }
});

var List = React.createClass({
  render: function(){
    return (
      <ul>
      {
        this.props.items.map(function(item) {
          return <li key={item}>{item}</li>
        })
       }
      </ul>
    )  
  }
});

React.renderComponent(<FilteredList/>,document.getElementById('mount-point'));

<!-- lang: html -->
<div id="mount-point"></div>

<!-- lang: css -->
* {
  box-sizing: border-box;
}

body {
  padding: 20px;
  background: #2c3e50;
}

.filter-list {
  margin: auto;
  width: 300px;
  background: #3498db;
  border-radius: 5px;
  border: 1px solid darken(#3498db,20%);
  input {
    width: 100%;
    display: block;
    padding: 10px;
    border-radius: 5px 5px 0px 0px;
    border: 0;
    font-size: 24px;
    &:focus {
      outline: none;
    }
  }
  ul {
    margin: 0;
    padding: 0;
    li {
      list-style-type: none;
      margin: 0;
      color: white;
      padding: 10px 20px;
      border-top: 1px solid darken(#3498db,20%);
      &:hover {
        background: #2980b9;
      }
    }
  }
}

#總結

我們已經介紹了一些 React 的基礎知識了,花點時間去看看 React API 和學一下 JSX

在學習 React 的下一張,我們將結合 Express 來創建一個在服務端渲染的應用,就像在客戶端一樣,然後使用 socket.io 來保持兩邊同步。

敬請期待!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom