[Full-stack] 快速上手開發 - React

故事背景


[1] 博客筆記結合《React快速上手開發》再次系統地、全面地走一遍。html

[2] React JS Tutorials:包含了JS --> React --> Redux --> Mobx 前端

 

 

項目部署


着眼於ful-stack全局,瞭解先後端的部署,以後才能深入理解react的角色與位置。java

1. 服務器部署react

[AWS] Deploy react project on EC2git

2. 用戶權限管理es6

[AWS] OAuth2.0github

[AWS] User managementweb

[AWS] Amazon Cognitoredux

3. 這就是將來後端的趨勢後端

[AWS] Serverless

 

 

React基本路線


1、靜態的html變爲了動態生成 

  • React本身的html表達方式
    <script> ReactDOM.render(
React.DOM.h1( {id:
"my-heading"}, React.DOM.span(null, React.DOM.em(null, "Hell"), "o" ), " world!" ),
document.getElementById(
'app')
);
</script>

 

  • 命名衝突:class, for, style
    <script>
      ReactDOM.render(
        /*
        // COUNTEREXAMPLE
        // this doesn't work
        React.DOM.h1(
          {
            class: "pretty",
            for : "me",
          },
          "Hello world!"
        ),
        */
        
        // PROPER EXAMPLE
        // this works
        React.DOM.h1(
          {
            className: "pretty",
            htmlFor : "me",
          },
          "Hello world!"
        ),        
        
        document.getElementById('app')
      );
    </script>

style卻是常常用到。

    <script>
      ReactDOM.render(
        /*
        // COUNTEREXAMPLE
        // this doesn't work
        React.DOM.h1(
          {
            style: "background: black; color: white; font-family: Verdana",
          },
          "Hello world!"
        ),
        */
        
        // PROPER EXAMPLE
        // this works
        React.DOM.h1(
          {
            style: {
              background: "black",
              color: "white",
              fontFamily: "Verdana",
            }
          },
          "Hello world!"
        ),      
        
        document.getElementById('app')
      );
    </script>

 

 

思考:可見以上的寫法,可讀性比較差,這也是以後引入JSX的重要緣由。

下圖中上面的JSX寫法就接近了原始的HTML格式,看起來更更爲習慣。

Goto for more details: [React] 01 - Intro: javaScript library for building user interfaces - React JSX

 

 

2、自定義組件纔是React的威力

  • 對React.DOM作了封裝
    <script>
var Component = React.createClass({ render: function() { return React.DOM.span(null, "I'm so custom"); } });
ReactDOM.render( React.createElement(Component),  // 這裏以前是React.DOM代碼,如今封裝了起來 document.getElementById(
"app") );
</script>

附加題:React 工廠方法——createFactory使用詳解【爲什麼感受用處不是很大】

 

  • props - 獲取屬性
    <script>
var Component = React.createClass({
/**
* 能夠採用PropTypes檢查props
*/

/**

* 若是沒有name屬性,會報錯,
* 能夠設置一個默認的
*/ render:
function() { return React.DOM.span(null, "My name is " + this.props.name); }
});
ReactDOM.render( React.createElement(Component, { name:
"Bob", }),

<Component name="Bob" /> // <---- 看來JSX的寫法更爲舒服,createElement看着彆扭!
document.getElementById(
"app") );
</script>

附加題:react demo10 (設置組件屬性的默認值getDefaultProps)

複合組件:Composite Component 表示 建立多個組件來合成一個組件,把組件的不一樣功能點進行分離。Goto for more details: [React] 01 - Intro: javaScript library for building user interfaces - 複合組件,React Props

子節點的獲取[React] 01 - Intro: javaScript library for building user interfaces - this.props.children

 

  • state - 經過狀態改變設置屬性
    <script>
      var TextAreaCounter = React.createClass({
        propTypes: {
          text: React.PropTypes.string,
        },
        getDefaultProps: function() {
          return {
            text: '',
          };
        },
        getInitialState: function() {
          return {
            text: this.props.text,
          };
        },
        _textChange: function(ev) {
          this.setState({            // Jeff: setState 觸發界面更新,由於這裏把prop變了
            text: ev.target.value,      // event.target:使用合成事件來消除瀏覽器之間的不一致狀況
          });
        },
        render: function() {
          return React.DOM.div(null,
            React.DOM.textarea({
              value   : this.state.text,
              onChange: this._textChange,
            }),
            React.DOM.h3(null, this.state.text.length)
          );
        }
      });
ReactDOM.render( React.createElement(TextAreaCounter, { text:
"Bob", // 這裏實際上是個初始值,因此命名爲defaultValue會好些 }), document.getElementById("app") ); </script>

附加題:事件處理,書p20。 

React 組件 API,除了setState,還有其餘6種方法:

    • 設置狀態:setState
    • 替換狀態:replaceState
    • 設置屬性:setProps
    • 替換屬性:replaceProps
    • 強制更新:forceUpdate
    • 獲取DOM節點:findDOMNode
    • 判斷組件掛載狀態:isMounted

 

  • 從外部訪問組件

如何定義」外部「?經過 myTextAreaCounter 設置新的state值 as following。

myTextAreaCounter.setState({text: "Hello outside world!" }); 

如下定義了myTextAreaCounter。

 <script>

var TextAreaCounter = React.createClass({
propTypes: { defaultValue: React.PropTypes.string, },
getInitialState:
function() { return { text: this.props.defaultValue, }; },
_textChange:
function(ev) { this.setState({ text: ev.target.value, }); },
render:
function() { return React.DOM.div(null, React.DOM.textarea({        // text --> input value : this.state.text, onChange: this._textChange, }), React.DOM.h3(null, this.state.text.length) ); }
});

---------------------------------------------------------
var myTextAreaCounter = ReactDOM.render( React.createElement(TextAreaCounter, { defaultValue: "Bob", }), document.getElementById("app") );
</script>

附加題:組件也算是代碼"分離思想"的一種體現,參看筆記:[React] 08 - Tutorial: evolution of code-behind【from HTML靜態頁面 to 複合組件】

 

  • 組件間的傳值

參見筆記 [React] 09 - Tutorial: components

 (11) 子組件向父組件傳值 - 子組件調用父組件的「方法」,以」函數指針「的相似形式;

 (12) 子組件之間的傳值 

 (13) 雙向數據綁定

 

 

[Redux]

經過這件事,讓咱們明白了Redux的重要性。

Goto for more details: [React] 02 - Intro: why react and its design pattern - 背後的思想:一步一步進化到 Redux

以及相關筆記: 

有必要另起一文走一遍!

 

 

3、組件的生命週期

  • 組件的建立

Ref: React建立組件的三種方式及其區別

    1. 函數式定義的無狀態組件
    2. es5原生方式React.createClass定義的組件  【`React.createClass`是react剛開始推薦的建立組件的方式,這是ES5的原生的JavaScript來實現的React組件】
    3. es6形式的extends React.Component定義的組件

隨着React的發展,React.createClass形式自身的問題暴露出來:

    • React.createClass 會自綁定函數方法(不像React.Component只綁定須要關心的函數)致使沒必要要的性能開銷,增長代碼過期的可能性。
    • React.createClass 的mixins不夠天然、直觀;
    • React.Component 形式很是適合高階組件(Higher Order Components -- HOC),它以更直觀的形式展現了比mixins更強大的功能,而且HOC是純淨的JavaScript,不用擔憂他們會被廢棄。
    • HOC 能夠參考 無狀態組件(Stateless Component) 與高階組件
    • mixins將死,ES6的Class不對其進行支持,HOC就是解決辦法。

 

(1) 當前老舊寫法:

var InputControlES5 = React.createClass({
propTypes: {
//定義傳入props中的屬性各類類型 initialValue: React.PropTypes.string }, defaultProps: { //組件默認的props對象 initialValue: '' }, // 設置 initial state getInitialState: function() {//組件相關的狀態對象 return { text: this.props.initialValue || 'placeholder' }; }, handleChange: function(event) { this.setState({ //this represents react component instance text: event.target.value }); }, render: function() { return ( <div> Type something: <input onChange={this.handleChange} value={this.state.text} /> </div> ); } });

--------如下沒區別------------------------
InputControlES5.propTypes
= { initialValue: React.PropTypes.string }; InputControlES5.defaultProps = { initialValue: '' };

 

(2) 將來推崇寫法:【其實就是使用了js6的類的新特性】

class InputControlES6 extends React.Component {
constructor(props) { super(props);
// 設置 初始狀態 this.state = { text: props.initialValue || 'placeholder' }; // ES6 類中函數必須手動綁定 this.handleChange = this.handleChange.bind(this);  // 建立的組件,其成員函數不會自動綁定this,須要開發者手動綁定,不然this不能獲取當前組件實例對象。  } handleChange(event) { this.setState({ text: event.target.value }); } render() { return ( <div> Type something: <input onChange={this.handleChange} value={this.state.text} /> </div> ); } }

React.Component
--------如下沒區別------------------------

InputControlES6.propTypes = {
    initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
    initialValue: ''
};

Jeff:
可是,使用類的概念後,意思就天然而然地跟着變了:
做爲組件類的屬性,不是組件實例的屬性,也就是所謂的類的靜態屬性來配置的。

 

經過bind鎖定this:

  1. 能夠在構造函數中完成綁定,【以上例子】
  2. 也能夠在調用時使用method.bind(this)來完成綁定,
  3. 還可使用arrow function來綁定。
<div onClick={this.handleClick.bind(this)}></div>    // 2.使用bind來綁定
<div onClick={()=>this.handleClick()}></div> // 3.使用arrow function來綁定

 

  • 無狀態組件

一、只要有可能,儘可能使用無狀態組件建立形式。

二、不然(如須要state、生命週期方法等),使用`React.Component`這種es6形式建立組件。

 

Ref: React中的無狀態和有狀態組件【原文看似不錯】

無狀態的函數寫法,又稱爲純組件SFC。它是一種只負責展現的純組件。 

對於這種無狀態的組件,使用函數式的方式聲明,會使得代碼的可讀性更好,並能大大減小代碼量,箭頭函數則是函數式寫法的最佳搭檔:

const Todo = (props) => (
    <li
        onClick={props.onClick}
        style={{textDecoration: props.complete ? "line-through" : "none"}}
    >
        {props.text}
    </li>
)

 

上面定義的 Todo 組件,輸入輸出數據徹底由props決定,並且不會產生任何反作用。

對於props爲 Object 類型時,咱們還可使用 ES6 的解構賦值:

const Todo = ({ onClick, complete, text, ...props }) => (
    <li
        onClick={onClick}
        style={{textDecoration: complete ? "line-through" : "none"}}
        {...props}
    >
        {props.text}
    </li>
)

無狀態組件通常會搭配高階組件(簡稱:HOC)一塊兒使用,高階組件用來託管state,Redux 框架就是經過 store 管理數據源和全部狀態,其中全部負責展現的組件都使用無狀態函數式的寫法。

這種模式被鼓勵在大型項目中儘量以簡單的寫法 來分割本來龐大的組件,而將來 React 也會面向這種無狀態的組件進行一些專門的優化,好比避免無心義的檢查或內存分配。因此建議你們儘量在項目中使用無狀態組件。

無狀態組件內部實際上是可使用ref功能的,雖然不能經過this.refs訪問到,可是能夠經過將ref內容保存到無狀態組件內部的一個本地變量中獲取到。

 

Ref: React無狀態組件——爲可複用而生

如何利用react提供的jsx語法寫好一個可複用的組件呢?---- 最經常使用的組件是「無狀態組件」

所謂無狀態,也能夠叫作無生命週期無state,組件是一個純jsx類或者對象。

這個組件內部沒有任何的生命週期和state狀態,那麼若是須要管理state狀態,該怎麼辦呢?---- Redux

# 這裏自定義了一個head主鍵,能夠複用,由於head的各部分細節由參數控制。

export class Header extends Component { render() { const {title, imgUrl, linkTo, bgColor}
= this.props
//提供4個接口參數給父容器作設置,能夠不傳參。 return ( <header className='header' style={bgColor}> {title} <Link to={linkTo} className="a_link" > <img src={imgUrl} className="a_img" /> </Link> </header> ) }
//嚴格來講,這些暴露給外部的參數都須要作驗證,經常使用的驗證類型爲array,bool,func,number,object,string static propTypes = { title: React.PropTypes.string.isRequired }
}
 

 

 

附加題:Mixins的支持不一樣 ----> 走向"高階組件"

For more details, go to: [React] 16 - Topic: Mixins & Higher-Order Components

React.Component這種形式並不支持Mixins,至今React團隊尚未給出一個該形式下的官方解決方案;

可是React開發者社區提供一個全新的方式來取代Mixins,那就是 Higher-Order Components

所謂 HOC:會返回組件的組件,Redux就是一個實現例子,可處理狀態。

 

因爲React團隊已經聲明 React.createClass最終會被React.Component的類形式所取代。

可是在找到Mixins替代方案以前是不會廢棄掉React.createClass形式。因此:

"能用React.Component建立的組件的就儘可能不用React.createClass形式建立組件"

 

 

  • 三個狀態,七個方法

參見筆記 [React] 09 - Tutorial: components,並結合raisl365系列 之 誘人的 react 視頻教程-基礎篇

【代碼有必要詳細研究與實踐】 

實驗代碼的基本思路是:

"點擊按鈕 ----> 改變某state ----> 觸發render ----> 經過if判斷語句,跳過某component的渲染 ----> 達到組件消失的效果「

 

 

 

路由:react-router


核心待解決的問題:沒有登陸的話,就沒有權限訪問這個路由。 

RR4 本次採用單代碼倉庫模型架構(monorepo),這意味者這個倉庫裏面有若干相互獨立的包,分別是:

  • react-router           # React Router 核心
  • react-router-dom              # 用於 DOM 綁定的 React Router
  • react-router-native       # 用於 React Native 的 React Router
  • react-router-redux         # React Router 和 Redux 的集成
  • react-router-config       # 靜態路由配置的小助手

 

1、傳統方式

[React] 05 - Route: connect with ExpressJS

[React] 06 - Route: koa makes your life easier

可見,路由的處理採用的是:在後端代碼中採用相似switch的方式判斷前端發來的URL request。

那麼問題來了,react是前端的東西,react-router是前端仍是後端?或者,是一個介於中間的東西?

答案是:前端路由!

 

 

2、React-router方式

參見:[React] 10 - Tutorial: router

Yuan Yifeng有整理:React Router 使用教程,在此補充些遺漏的內容。

Ref: 官方路由示範代碼

 

  • 嵌套路由 + hash

如此,不用使用關鍵字:exact

用戶訪問/repos時,

    1. 先加載App組件,
    2. 而後在它的內部再加載Repos組件。
<Router history={hashHistory}>
  <Route path="/" component={App}>
    <Route path="/repos" component={Repos}/>
    <Route path="/about" component={About}/>
  </Route>
</Router>

URL with hash value.

http://localhost:8080/#/about?_k=z86gvy

  

  • props.children
export default React.createClass({
  render() {
    return (
      <div>
        <h1>React Router Tutorial</h1>
        <ul role="nav">
          <li><Link to="/about">About</Link></li>
          <li><Link to="/repos">Repos</Link></li>
        </ul>
        {this.props.children}
      </div>
    )
  }
})

Result:  

 

  • ... this.props

導入全部的參數並展開

<ul role="nav">
<li><NavLink to="/about">About</NavLink></li>
<li><NavLink to="/repos">Repos</NavLink></li>
</ul>

將Link 統一變爲記錄活動狀態帶有顏色的link。

  render() {
    return <Link {...this.props} activeClassName="active"/>
  }

 

更多內容:

詳見 [React] 10 - Tutorial: router - URL的參數處理 

 

  • 其餘內容

11、表單處理

12、路由的鉤子

 

 

Jeff: 以上即是react周邊最爲親近的一些知識點

相關文章
相關標籤/搜索