2017年7月8日 星期六

React.js (2) - JSX, Component 基礎應用程式架構

以下為 JSX, Component 筆記。
本文之 Demo 會製作一個像 Angular.js 第一次會做的 ng-model 綁定來做 input 跟著文字走的應用程式。


JSX

JSX 最大特色就是可以在 Javascript 中寫 XML 標籤,最後這個 JSX 將會被渲染在網頁上,而這個 JSX 不是一會看到的 Component : <TextInput initText="something" /> , JSX 只是普通的 HTML 而已,也可以匯入其它 Component : <TextInput initText="something" /> 來當作是 JSX 接受的 XML 標籤,其功能一樣會被渲染。

JSX 會撰寫在 Function 中,或是那些 Arrow Function, 總之就是在可以 return 的方法函式中,丟出 html,像是:

const showTitle = ()=>( 
 <h1> This is title ~ </h1>
)

或是放在 return 裡面:
function showTitle(){
    return <h1> This is title ~ </h1>
}

//or

class showTitle extends React.Component{
    constructor(){ super(); }
    render(){
        return (<h1> This is title ~ </h1>)
    }
}

傳入參數


如果要在 JSX 套用值的參數,或寫 javascript ,只要使用大括號即可:

//第一種寫法
const showTitle = (props:{text:string})=>( 
 <h1> This is title ~ {props.text} </h1>
)

//第二種寫法
function showTitle(props:{text:string}){ 
    return <h1> This is title ~ {props.text} </h1>
}

//第三種寫法
type Props = {
    text : string
}
class showTitle extends React.Component{
    constructor( props: Props ){ super(props); }
    render(){
        return (<h1> This is title ~ {this.props.text} </h1>)
    }
}

假設需要用到 javascript 程式,直接在大括號中寫也可以,跑迴圈的話,直接把 JSX 寫出來,渲染時就會把標籤打出來了。

含子層級 JSX 的渲染


剛才看過的 JSX 都是只有一層 <TextInput initText="sss" /> ,要進行多層級的 JSX ,只要把值帶入到 children 就可以了:

const TextShow = ({children}:{children? : React$Element<*> }) =>(
 <h1>{ children }</h1>
)

用的時候就可以包成多層級的 JSX:
<TextShow> hello world </TextShow>

其他用法暫不在此紀錄。

只有一個 JSX 


另外, JSX 在 return 時,只能渲染一個元素,不能把元素同時輸出在 return,像是: return (<h1></h1>, <h1></h1>) ,這是不合法的,解決方案是把這兩個元素包成一個元素,像是:

return ( <div> <h1> </h1> <h1></h1></div>) 。

Component

Component 其實就是剛才看到的那些 function , return 出來的 xml 那些標籤則屬於 JSX 的範圍,不過剛才的程式碼使用上是會有問題的,所以必須先看過 Component 的一些規則。

將程式寫成 Component ,是為了將 JSX 那些 HTML 輸出,成為一個應用程式,所以 Component 最後會變成: <component [argument]="參數" /> ,然後這個 component 呼叫後會在 html 顯示那些 jsx 渲染的內容。

模組概念

通常一個 .js, .jsx (一般來說都是一樣的檔案,只是有些人習慣只要寫到 jsx ,就會取名成 .jsx )的檔案,會當作一個模組來看待,一個基礎的模組,在使用上會有這幾個步驟:

匯出
export default [Function 名稱];

匯入
import [Module 名稱] from '[./path/to/file]'

要是不寫匯出, react 編譯就會噴錯給你看,所以要記得檢查一下是否有寫匯出了。

React.Component

只要所有 jsx 的模組,在開頭的時候一定要先匯入 React 這個模組, component 則會負責處理,不管是匿名 function, function, 或 class 都一樣:
import React from 'react';

//當純只要 component 了話:
import react{Component} from 'react';

InputText 程式 (按照 React.js 執行順序倒反)

TextShow.js:
import React from 'react'

const TextShow = ( props : {text:string}) =>( // props: 裡面包含型態,這是 flow-bin, 不寫的話,會變成 {text}, 如果是這樣,下面也把 props.text 改成 text。
 <h1>{ props.text }</h1>
)

export default TextShow;

TextInput.js:
import React from 'react'
import TextShow from './TextShow'

type Props = { //用了 flow-bin ,所以先定義這個 props 的型態,包含裡面有什麼參數
 initText : string
}

class TextInput extends React.Component{

 state:{ //每個 component class 都有一個 state 可以定義,裡面可以裝重要的參數,而 react 也會監視這些參數
  text:string
 }

 constructor(props : Props){ //初始化要傳入的參數,有 flow-bin 定義,不定義的話則是 props 而已,沒有 props: Props
  super(props); //把參數傳到父類別

  this.state = {
   text : ''
  }
 }

 handleChange = (e : Event)=>{
  if(e.target instanceof HTMLInputElement){
   this.setState({ //不可以直接用 this.state.text = '', 會出錯,所以請用 this.setState({}) 來寫。
    text: e.target.value
   });
  }
 }

 render(){
  return ( //回傳 jsx,注意這裡 return 不是大括號,是 () 而已。
   <div>
   <input type="text" placeholder={this.props.initText} onChange={this.handleChange} value={this.state.text} />
   <TextShow text={this.state.text} />
   </div>
  )
 }

}

export default TextInput

App.js:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import TextInput from './TextInput'

class App extends Component {
  render() {
    return ( //最終的 SPA 應用程式呼叫 Component 內容。
      <TextInput initText="typing something..." />
    );
  }
}

export default App;

Reference:
http://ithelp.ithome.com.tw/articles/10186982
https://facebook.github.io/react/docs/components-and-props.html
https://facebook.github.io/react/docs/installation.html#creating-a-new-application
http://blog.techbridge.cc/2016/07/30/react-dev-enviroment-webpack-browserify/
http://ithelp.ithome.com.tw/articles/10186845
https://github.com/eyesofkids/ironman2017/blob/master/day19_todolist_style/src/components/TodoList.js
http://ithelp.ithome.com.tw/users/20103131/ironman/1012
https://flow.org/

沒有留言:

張貼留言

© ERIC RILEY , 自由無須告知轉貼
Background Japanese Sayagata by Olga Libby