# Module、Component
###### tags: `React` `Javascript`
**1.Module 模組**
將可共用的js拆分成個別的檔案
**2.Component元件**
將個別布局的html/css/js/image拆分出來的集合,
兩者的目的都是重用、簡化、提高效率,但是規模不同
React 提供兩種Component
1. 函數式(簡單
<script type="text/babel">
function Demo(){//必須為大寫開頭
console.log(this);//babel編譯時會套上嚴格模式而此模式禁止自定義函數內this指向window因此這邊為undefined
return <h1>test</h1>;//必須有傳回值
}
ReactDom.render("<Demo/>",domcument.getElementById(''test));//使用標籤綁定到component
/*
執行步驟
1. react 解析組件標籤後找到Demo
2. 調用Demo將回傳的虛擬Dom轉為真實Dom
*/
</script>
2. 類式(複雜
class Demo extends React.Component { //必須繼承React.Component
render(){ //必須定義render 且回傳
//render中的this代表的會是Demo的實例對象
return (
<h1>test</h1>
)
}
}
ReactDom.render("<Demo/>",domcument.getElementById(''test));//使用標籤綁定到component
/*
執行步驟
1. react 解析組件標籤後找到Demo
2. 發現組件是使用類定義的,隨後new出來該類的實例,並且調用原型物件上的render方法
*/
簡單與複雜的差異為有狀態
組件"實例"的三大核心
1. state :
- 透過建構子可在類別中初始化state 而此屬性必須為object
- 狀態不可以直接更改,要用react api this.setState
- 更新的動作為合併 merge
- 改變狀態後會react會呼叫render
基本寫法
<script type="text/babel">
class Demo extends React.Component {
constructor(props){
super(props)
this.change= this.change.bind(this);
this.state = { test : true }
}
render(){
return (
<button onClick={this.change}/>
)
}
change(){
const test = this.state.test;
this.setState({test : !test });
}
}
</script>
簡化寫法
<script type="text/babel">
class Demo extends React.Component {
state = { test : true }
render(){
return (
<button onClick={this.change}/>
)
}
change = ()=>{
const test = this.state.test;
this.setState({test : !test });
}
}
</script>
2. props
- props是唯讀的
- 對傳入參數的限制建議寫在類中
- 參數由react自動傳入,但也可建立建構子傳入並丟給super來設定,如果建構子沒有接收傳入參數會導致在建構子中使用this.props獲取不到傳入參數
基本設定參數、使用參數語法
<script type="text/babel">
class Demo extends React.Component {
render(){
const { name , age } = this.props;
return (
<ul>
<li>name : {name}</li>
<li>age : {age}</li>
</ul>
)
}
}
//函數式組建可使用傳入參數,會將標籤屬性組成一個物件
//而傳入參數限制則只能定義在外側
function Demo2(props){
const {name,age} = props;
return (
<ul>
<li>name : {name}</li>
<li>age : {age}</li>
</ul>
)
}
//1.最基本寫法 要注意如果傳入值有形別則要用{}的方式型別才會正確
ReactDom.render('<Demo name="tom" age={10} / >' , document.getElementById('tag'));
//2.基本寫法
const p = {name : "tom" , age :27}
ReactDom.render('<Demo name={p.name} age={p.age} / >' , document.getElementById('tag'));
//3.進階寫法 => 有條件限制:傳入的key同物件的key
//這個寫法的 { ...p } 與es的展開運算符不同,雖然結果是展開物件,但這是babel與react特有的定義且只有在標籤中有效
ReactDom.render('<Demo {...p}/ >' , document.getElementById('tag'));
</script>
對props進行限制( required 、 type ..
需要引入prop-types.js => PropTypes
<script type="text/babel">
class Demo extends React.Component {
//同下方的定義方式
static propsTypes = {
name : PropTypes.string.isRequired,
age : PropTypes.number,
speak : PropTypes.func
}
static defaultProps= {
age : 18
}
state = { test : true }
render(){
return (
<button onClick={this.change}/>
)
}
}
//將會限制name為字串且必傳、age為數字、speak為函數
Demo.propsTypes = {
name : PropTypes.string.isRequired,
age : PropTypes.number,
speak : PropTypes.func
}
//指定age預設為18
Demo.defaultProps= {
age : 18
}
function speak(){}
ReactDom.render('<Demo name="tom" age={10} speak={speak}/ >' , document.getElementById('tag'));
</script>
3. refs
1.字串型refs => 將dom保存進refs ps將廢棄 原因是效率問題
2.call back function => react呼叫回調函式時會傳入目前節點,透過箭頭函數的this特性將節點設定到實例上
當call back function直接寫在標籤上時會造成一個現象,畫面在初始化時只會調用一次但是在重新render時會呼叫兩次第一次會傳入null第二次會正確傳入dom 透過把函數綁定在類別內可解決這個問題 ps react在render時建立新的函數實例,所以react會有一個清空refs的動作
3.createRef : React提供建立一個容器來儲存ref該容器是專人專用
<script type="text/babel">
class Demo extends React.Component {
input3 = React.createRef();
check = ()=>{
const {input1}= this.refs
alert(input1.value)
alert(input2.value)
alert(input3.current.value) // 固定用法
}
render(){
return (
<div>
<input ref="input1" / > // 1.字串型
<input ref={ (node) => {this.input2 = node }} / > //2.call back function
<input ref={this.input3} / >
<button onClick={this.check}/>
</div>
)
}
}
</script>
---
在import時以資料夾區隔,若檔名為index時可以指定到資料夾而不用指定到js
import Hello from './component/Hello';//實際上Hello內還有index.js