iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
自我挑戰組

登堂入室!前端工程師的觀念技術 _30_ 題系列 第 27

26. Redux 的用途 & 入門實作 (下)

這篇來把上一篇跳過的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


action 是一種 JS的物件,代表 state 要執行的改變。

Action 是讓 data 進到 store 的唯一方式。任何 data,無論是從 UI 事件、網路 callback、或其他來源,像是 WebSocket 最後都需要作為 action 被 dispatch(派遣;發送)。

  • action creator
    產生 action 的 function,呼叫 action creator 會產生一個 action,但並不會 dispatch action。如果要實際進行操作,必須呼叫 store 的 dispatch function。

進到範例,我們先指定一個action要執行的動作,在程式碼加入這幾行:

// 要對state執行的動作
const actions = {
  addContact: name => {  // 新增一個叫做addContact的action,參數為name
    return {
      type: "ADD_CONTACT",   // 先指定action的type
      id: uuid.v4(),
      name
    };
  }
};

addContact會回傳屬性typeid和傳入的參數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);
}
  • bindActionCreators
    bindActionCreators 只有一種使用情境: 想將 action creator 傳遞給一個 component,但不打算把 dispatch 或 store 傳遞進去。
    action creator 會被包進一個 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()不熟悉,後面寫的比較詳細,可以看完再回來理解。)

super(props)

如果沒有初始化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

使用建構式有兩個目的:

  1. 藉由指派一個物件(object)給this.state,作為local state初始化。
  2. 將事件處理器(event handler)綁定給一個實例(instance)。

不能在建構式裡執行 setState()

super 關鍵字必須出現在this 關鍵字之前使用,super 關鍵字也可以使用在呼叫函式與父對象。

Refs & DOM

Ref 提供了一種可以取得 DOM 節點或在 render 方法內建立 React element 的方式。

Ref 的值會根據節點的類型而有所不同:

  • 在 HTML element 上使用 ref 參數時
    React.createRef() 建立 ref 會取得 HTML element 底下的 DOM element 來做為它的 current 屬性。
  • 在客製化的 class component 使用 ref 參數時
    ref 取得 被 mount 的 component 上的 instance 來當作他的 current。
  • function component 因為沒有 instance,不能使用 ref。

【如內文有誤還請不吝指教>< 並感謝閱覽至此的各位:D 】

參考資料

---正文結束---

昨天臨時有事沒辦法寫文,竟然在倒數5天失敗了QQ 但我還是會把文章寫完的!


上一篇
25. Redux 的用途 & 入門實作 (上)
下一篇
27. 解釋 CSS 的 BFC(Block Formatting Context)
系列文
登堂入室!前端工程師的觀念技術 _30_ 題31

尚未有邦友留言

立即登入留言