Apa itu mapDispatchToProps?

358

Saya sedang membaca dokumentasi untuk perpustakaan Redux dan memiliki contoh ini:

Selain membaca keadaan, komponen kontainer dapat mengirim tindakan. Dengan cara yang sama, Anda bisa mendefinisikan fungsi yang dipanggil mapDispatchToProps()yang menerima dispatch()metode dan mengembalikan alat-alat panggilan balik yang ingin Anda masukkan ke dalam komponen presentasi.

Ini sebenarnya tidak masuk akal. Mengapa Anda butuhkan mapDispatchToPropssaat Anda sudah memiliki mapStateToProps?

Mereka juga menyediakan contoh kode praktis ini:

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

Bisakah seseorang tolong jelaskan dalam istilah awam apa fungsi ini dan mengapa ini berguna?

Pembisik kode
sumber

Jawaban:

577

Saya merasa tidak ada jawaban yang mengkristal mengapa mapDispatchToPropsberguna.

Ini benar-benar hanya dapat dijawab dalam konteks container-componentpola, yang saya temukan paling baik dipahami dengan membaca pertama: Komponen Kontainer kemudian Penggunaan dengan Bereaksi .

Singkatnya, Anda componentsseharusnya hanya peduli dengan menampilkan barang-barang. Satu- satunya tempat mereka seharusnya mendapatkan informasi adalah alat peraga mereka .

Dipisahkan dari "menampilkan barang" (komponen) adalah:

  • bagaimana Anda mendapatkan barang untuk ditampilkan,
  • dan bagaimana Anda menangani acara.

Itu untuk apa containers.

Oleh karena itu, "dirancang dengan baik" componentdalam pola terlihat seperti ini:

class FancyAlerter extends Component {
    sendAlert = () => {
        this.props.sendTheAlert()
    }

    render() {
        <div>
          <h1>Today's Fancy Alert is {this.props.fancyInfo}</h1>
          <Button onClick={sendAlert}/>
        </div>
     }
}

Lihat bagaimana komponen ini mendapat info ini akan menampilkan dari alat peraga (yang datang dari toko redux melalui mapStateToProps) dan juga mendapat fungsi aksinya dari alat peraga nya: sendTheAlert().

Di situlah mapDispatchToPropsmasuk: dalam yang sesuaicontainer

// FancyButtonContainer.js

function mapDispatchToProps(dispatch) {
    return({
        sendTheAlert: () => {dispatch(ALERT_ACTION)}
    })
}

function mapStateToProps(state) {
    return({fancyInfo: "Fancy this:" + state.currentFunnyString})
}

export const FancyButtonContainer = connect(
    mapStateToProps, mapDispatchToProps)(
    FancyAlerter
)

Aku ingin tahu apakah Anda bisa lihat, sekarang bahwa itu adalah container 1 yang tahu tentang redux dan pengiriman dan menyimpan dan negara dan ... hal.

Dalam componentpola,, FancyAlerteryang melakukan rendering tidak perlu tahu tentang hal-hal itu: ia mendapatkan metodenya untuk memanggil onClicktombol, melalui alat peraga.

Dan ... mapDispatchToPropsadalah alat yang berguna yang disediakan redux untuk membiarkan wadah dengan mudah melewatkan fungsi itu ke komponen terbungkus pada alat peraga.

Semua ini sangat mirip dengan contoh todo dalam dokumen, dan jawaban lain di sini, tetapi saya telah mencoba memberikannya pada pola untuk menekankan alasannya .

(Catatan: Anda tidak dapat menggunakan mapStateToPropsuntuk tujuan yang sama seperti mapDispatchToPropsuntuk alasan dasar bahwa Anda tidak memiliki akses ke dispatchdalam mapStateToProp. Jadi, Anda tidak dapat menggunakan mapStateToPropsmetode komponen yang digunakan komponen terbungkus dengan metode yang digunakan dispatch.

Saya tidak tahu mengapa mereka memilih untuk memecahnya menjadi dua fungsi pemetaan - mungkin lebih rapi untuk memiliki mapToProps(state, dispatch, props) IE satu fungsi untuk melakukan keduanya!


1 Catat bahwa saya sengaja menamakan wadah itu FancyButtonContainer, untuk menyoroti bahwa itu adalah "benda" - identitas (dan karenanya keberadaan!) Dari wadah itu sebagai "benda" kadang-kadang hilang di steno.

export default connect(...) ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

sintaks yang ditunjukkan dalam kebanyakan contoh

GreenAsJade
sumber
5
Saya masih ingin tahu: Bagaimana dengan fungsionalitas yang diperlukan tidak dapat ditangani dengan langsung memanggil store.dispatch dari dalam suatu komponen?
pixelpax
8
@ user2130130 Tidak ada. Ini tentang desain yang bagus. Jika Anda menggabungkan komponen Anda ke store.dispatch, maka ketika Anda memutuskan untuk faktor redux, atau ingin menggunakannya di beberapa tempat yang tidak berbasis redxu (atau hal lain yang tidak bisa saya pikirkan sekarang) Anda terjebak dengan banyak perubahan. Pertanyaan Anda bersifat umum untuk "mengapa kita repot-repot dengan 'praktik desain yang baik' - Anda mendapatkan fungsionalitas yang sama dengan kode Anda". mapDispatchToProps disediakan sehingga Anda dapat menulis komponen yang dirancang dengan baik dan dipisahkan secara bersih.
GreenAsJade
4
Apa yang saya benar-benar tidak dapatkan di sini adalah apa: ALERT_ACTIONapakah fungsi tindakan atau typeyang dikembalikan dari fungsi tindakan? : / so baffed
Jamie Hutber
1
@JamieHutber Ketat, ALERT_ACTION tidak ada hubungannya dengan pertanyaan ini. Ini adalah argumen yang valid untuk dikirim, dan seperti yang terjadi, dalam kode saya itu berasal dari "action builder", yang mengembalikan objek yang dikirim menggunakan, seperti yang dijelaskan redux.js.org/docs/api/Store.html#dispatch . Poin utama di sini adalah bahwa cara memanggil pengiriman dijelaskan dalam wadah dan diteruskan pada alat peraga komponen. Komponen hanya mendapat fungsi dari alat peraga, di tempat lain. Cara "salah" melakukannya dalam pola ini adalah dengan mengirimkan pengiriman ke komponen dan melakukan panggilan yang sama dalam komponen.
GreenAsJade
1
Jika Anda memiliki beberapa pembuat tindakan yang perlu diteruskan ke komponen anak sebagai alat peraga, salah satu alternatif adalah membungkusnya dengan bindActionCreators di dalam mapDispatchToProps (lihat redux.js.org/docs/api/bindActionCreators.html ); alternatif lain adalah dengan hanya menyediakan objek pembuat tindakan untuk terhubung (), misalnya, terhubung (mapStateToProps, {actioncreators}), react-redux akan membungkusnya dengan pengiriman () untuk Anda.
dave
81

Ini pada dasarnya sebuah steno. Jadi alih-alih harus menulis:

this.props.dispatch(toggleTodo(id));

Anda akan menggunakan mapDispatchToProps seperti yang ditunjukkan dalam kode contoh Anda, dan kemudian menulis di tempat lain:

this.props.onTodoClick(id);

atau lebih mungkin dalam hal ini, Anda akan memilikinya sebagai pengendali acara:

<MyComponent onClick={this.props.onTodoClick} />

Ada video bermanfaat oleh Dan Abramov tentang ini di sini: https://egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist

hamstu
sumber
Terima kasih. Saya juga bertanya-tanya, bagaimana cara pengiriman ditambahkan ke alat peraga di tempat pertama?
Code Whisperer
14
Jika Anda tidak menyediakan mapDispatchfungsi Anda sendiri , Redux akan menggunakan default. mapDispatchFungsi default itu hanya mengambil dispatchreferensi fungsi, dan memberikannya kepada Anda sebagai this.props.dispatch.
markerikson
7
Metode pengiriman diturunkan oleh Komponen Penyedia
Diego Haz
55

mapStateToProps()adalah utilitas yang membantu komponen Anda mendapatkan status yang diperbarui (yang diperbarui oleh beberapa komponen lain),
mapDispatchToProps()adalah utilitas yang akan membantu komponen Anda untuk memecat suatu peristiwa aksi (tindakan pengiriman yang dapat menyebabkan perubahan status aplikasi)

Saisurya Kattamuri
sumber
23

mapStateToProps, mapDispatchToPropsdan connectdari react-reduxperpustakaan menyediakan cara mudah untuk mengakses statedan dispatchfungsi toko Anda. Jadi pada dasarnya terhubung adalah komponen urutan yang lebih tinggi, Anda juga dapat berpikir sebagai pembungkus jika ini masuk akal untuk Anda. Jadi setiap kali Anda statediubah mapStateToPropsakan dipanggil dengan yang baru statedan selanjutnya saat Anda propsmemperbarui komponen akan menjalankan fungsi render untuk merender komponen Anda di browser. mapDispatchToPropsjuga menyimpan nilai-nilai kunci pada propskomponen Anda, biasanya mereka mengambil bentuk fungsi. Sedemikian rupa Anda dapat memicu stateperubahan dari komponen Anda onClick, onChangeacara.

Dari dokumen:

const TodoListComponent = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

function toggleTodo(index) {
  return { type: TOGGLE_TODO, index }
}

const TodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList) 

Juga pastikan bahwa Anda terbiasa dengan Bereaksi fungsi stateless dan Komponen Orde Tinggi

Vlad Filimon
sumber
Jadi pengiriman seperti acara pada dasarnya?
Code Whisperer
2
Itu bisa terkait dengan acara, pengiriman hanya fungsi dan satu-satunya cara untuk mengubah status aplikasi Anda . mapStateToProps adalah salah satu cara untuk mengekspos fungsi pengiriman toko Anda ke React Component. Juga catat bahwa connect bukan merupakan bagian dari redux sebenarnya itu hanyalah utilitas dan boilerplate mengurangi library yang disebut react-redux untuk bekerja dengan react dan redux. Anda dapat mencapai hasil yang sama tanpa reux-redux jika Anda meneruskan toko Anda dari komponen reaksi root ke anak-anak.
Vlad Filimon
3

mapStateToPropsmenerima statedan propsdan memungkinkan Anda untuk mengekstrak alat peraga dari negara bagian untuk lolos ke komponen.

mapDispatchToPropsmenerima dispatchdan propsdan dimaksudkan bagi Anda untuk mengikat pembuat tindakan untuk dikirim sehingga ketika Anda menjalankan fungsi yang dihasilkan tindakan akan dikirim.

Saya menemukan ini hanya menyelamatkan Anda dari keharusan melakukan dispatch(actionCreator())dalam komponen Anda sehingga membuatnya sedikit lebih mudah dibaca.

https://github.com/reactjs/react-redux/blob/master/docs/api.md#arguments

Harry Moreno
sumber
Terima kasih tetapi apa nilai dispatchmetodenya? Dari mana asalnya?
Code Whisperer
oh Pengiriman pada dasarnya membuat aksi memulai aliran searah reduks / fluks. Jawaban lain tampaknya menjawab pertanyaan Anda lebih baik dari ini.
Harry Moreno
Juga, metode pengiriman berasal dari perangkat tambahan yang disediakan oleh <Provider/>dirinya sendiri. Itu melakukan sihir komponen tingkat tinggi sendiri untuk menjamin bahwa pengiriman tersedia di komponen anak-anaknya.
Ricardo Magalhães
3

Sekarang anggaplah ada tindakan untuk redux sebagai:

export function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

Ketika Anda mengimpornya,

import {addTodo} from './actions';

class Greeting extends React.Component {

    handleOnClick = () => {
        this.props.onTodoClick(); // This prop acts as key to callback prop for mapDispatchToProps
    }

    render() {
        return <button onClick={this.handleOnClick}>Hello Redux</button>;
    }
}

const mapDispatchToProps = dispatch => {
    return {
      onTodoClick: () => { // handles onTodoClick prop's call here
        dispatch(addTodo())
      }
    }
}

export default connect(
    null,
    mapDispatchToProps
)(Greeting);

Seperti nama fungsi mengatakan mapDispatchToProps(), dispatchtindakan peta untuk alat peraga (alat peraga komponen kami)

Jadi prop onTodoClickadalah kunci mapDispatchToPropsfungsi yang selanjutnya didelegasikan untuk mengirim tindakan addTodo.

Juga jika Anda ingin memangkas kode dan memotong implementasi manual, maka Anda dapat melakukan ini,

import {addTodo} from './actions';
class Greeting extends React.Component {

    handleOnClick = () => {
        this.props.addTodo();
    }

    render() {
        return <button onClick={this.handleOnClick}>Hello Redux</button>;
    }
}

export default connect(
    null,
    {addTodo}
)(Greeting);

Yang persis berarti

const mapDispatchToProps = dispatch => {
    return {
      addTodo: () => { 
        dispatch(addTodo())
      }
    }
}
Temui Zaveri
sumber