這篇來把上一篇跳過的action補上,然後會補充一點之前沒講過的super()
和React Refs。
上一次完成到建立store到顯示資料,今天會使用action操作資料!
首先,新增要使用的class component。
class AddContact extends React.Component {
handleSubmit = (event) => {
event.preventDefault();
};
render() {
return (
<div className="box">
<form onSubmit={this.handleSubmit}>
<div className="field">
<label className="label">Name</label>
<div className="control">
<input
className="input"
type="text"
placeholder="John Doe"
/>
</div>
</div>
<button type="submit" className="button">
Add contact
</button>
</form>
</div>
);
}
}
寫完component,要記得渲染到畫面上:
class App extends React.Component {
render() {
return (
<section className="section">
<h1 className="title">Contacts</h1>
<AddContact/> // 加入AddContact元件
<Contacts
contacts={this.props.contacts}
/>
</section>
);
}
}
這裡先完成輸入框的外觀,接下來要慢慢完成實際的作用。
onSubmit={this.handleSubmit}
是用來防止提交表單,
我自己習慣寫到form就會先加preventDefault()
,不然按到送出頁面會跑掉,有點麻煩。
action 是一種 JS的物件,代表 state 要執行的改變。
Action 是讓 data 進到 store 的唯一方式。任何 data,無論是從 UI 事件、網路 callback、或其他來源,像是 WebSocket 最後都需要作為 action 被 dispatch(派遣;發送)。
進到範例,我們先指定一個action要執行的動作,在程式碼加入這幾行:
// 要對state執行的動作
const actions = {
addContact: name => { // 新增一個叫做addContact的action,參數為name
return {
type: "ADD_CONTACT", // 先指定action的type
id: uuid.v4(),
name
};
}
};
addContact
會回傳屬性type
、id
和傳入的參數name
。
action必須指定一個type,這裡指定的type名為"ADD_CONTACT"。
id和name就是我們一開始的store裡的資料格式!
id一樣會隨機產生,name則是輸入框輸入的值。
然後看到上次已經完成的reducer,在裡面的switch
多設定一種情況(case
):
const reducer = (state = {}, action) => {
switch (action.type) {
// 新增情境
case "ADD_CONTACT":
const { name } = action; // 取得action裡的name property
return [{ name }, ...state]; // 回傳action的陣列
default:
return state;
}
}
因為要把action傳給component,這裡使用bindActionCreators。
import { bindActionCreators } from Redux
const mapDispatchToProps = dispatch => {
return bindActionCreators(actions, dispatch);
}
記得還要連結component和寫好的 mapDispatchToProps
才有用:
// AppContainer接收connect處理好 mapStateToProps,mapDispatchToProps和 App的結果
const AppContainer = connect(mapStateToProps,mapDispatchToProps)(App);
這樣就可以把寫好的actions傳進component使用了!
<AddContact addContact={this.props.addContact}/>
到這裡是action的定義到設定,接下來會真正對資料進行操作。
回到文章最開始寫的component,
最後要去得實際input的值,把他新增到store。
class AddContact extends React.Component {
// 建構子
constructor(props) {
// calls the parent constructor(= React.Component).
super(props);
// 產生一個可以儲存 textInput DOM element 的 ref
this.textInput = React.createRef();
}
handleSubmit = (event) => {
event.preventDefault();
// 利用「current.value」來取得 DOM 節點的值
this.props.addContact(this.textInput.current.value);
};
render() {
...
<input
className="input"
type="text"
ref={this.textInput} // 指定ref的值
placeholder="John Doe"
/>
}
}
這樣應該就能成功新增資料了!
附上 codepen完整程式碼
( 如果對super
和.createRef()
不熟悉,後面寫的比較詳細,可以看完再回來理解。)
如果沒有初始化state和綁定方法(methods),就不需要執行建構式(constructor)。
If you don’t initialize state and you don’t bind methods, you don’t need to implement a constructor for your React component.
必須在敘述式前呼叫super(props),否則this.props
會是undefined
,可能導致錯誤。
you should call super(props) before any other statement. Otherwise, this.props will be undefined in the constructor
使用建構式有兩個目的:
this.state
,作為local state初始化。不能在建構式裡執行 setState()
。
super 關鍵字必須出現在this 關鍵字之前使用,super 關鍵字也可以使用在呼叫函式與父對象。
Ref 提供了一種可以取得 DOM 節點或在 render 方法內建立 React element 的方式。
Ref 的值會根據節點的類型而有所不同:
React.createRef()
建立 ref 會取得 HTML element 底下的 DOM element 來做為它的 current 屬性。【如內文有誤還請不吝指教>< 並感謝閱覽至此的各位:D 】
參考資料
---正文結束---
昨天臨時有事沒辦法寫文,竟然在倒數5天失敗了QQ 但我還是會把文章寫完的!