本文之 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;
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/
沒有留言:
張貼留言