Dokumen Redux untuk bindActionCreators menyatakan bahwa:
Satu-satunya kasus penggunaan
bindActionCreators
adalah ketika Anda ingin meneruskan beberapa pembuat tindakan ke komponen yang tidak mengetahui Redux, dan Anda tidak ingin meneruskan pengiriman atau penyimpanan Redux ke sana.
Apa contoh yang bindActionCreators
akan digunakan / dibutuhkan?
Jenis komponen apa yang tidak mengetahui Redux ?
Apa keuntungan / kerugian dari kedua opsi tersebut?
//actionCreator
import * as actionCreators from './actionCreators'
function mapStateToProps(state) {
return {
posts: state.posts,
comments: state.comments
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionCreators, dispatch)
}
vs.
function mapStateToProps(state) {
return {
posts: state.posts,
comments: state.comments
}
}
function mapDispatchToProps(dispatch) {
return {
someCallback: (postId, index) => {
dispatch({
type: 'REMOVE_COMMENT',
postId,
index
})
}
}
}
sumber
#3
merupakan singkatan dari opsi#1
?mapDispatchToProps
:function
,object
dan hilang. Cara menangani setiap kasus dijelaskan di siniredux
danconnect
danaddDispatchToProps
untuk komponen sederhana tampaknya berlebihan jika saya bisa melewatkan satu prop ke bawah. Tapi sejauh yang saya tahu hampir semua kasus untukmapDispatch
props akan menjadi opsi#1
atau#3
disebutkan dalam jawaban99% dari waktu, ini digunakan dengan fungsi React-Redux
connect()
, sebagai bagian darimapDispatchToProps
parameter. Ini dapat digunakan secara eksplisit di dalammapDispatch
fungsi yang Anda sediakan, atau secara otomatis jika Anda menggunakan sintaks singkat objek dan meneruskan objek yang penuh dengan pembuat tindakanconnect
.Idenya adalah bahwa dengan mengikat sebelumnya pembuat tindakan, komponen yang Anda berikan secara
connect()
teknis "tidak tahu" bahwa itu terhubung - hanya tahu bahwa itu perlu dijalankanthis.props.someCallback()
. Di sisi lain, jika Anda tidak mengikat pembuat tindakan, dan meneleponthis.props.dispatch(someActionCreator())
, sekarang komponen "tahu" bahwa itu terhubung karena mengharapkanprops.dispatch
ada.Saya menulis beberapa pemikiran tentang topik ini di posting blog saya Idiomatic Redux: Mengapa menggunakan pembuat tindakan? .
sumber
Contoh yang lebih lengkap, berikan objek yang penuh dengan pembuat aksi untuk dihubungkan:
import * as ProductActions from './ProductActions'; // component part export function Product({ name, description }) { return <div> <button onClick={this.props.addProduct}>Add a product</button> </div> } // container part function mapStateToProps(state) { return {...state}; } function mapDispatchToProps(dispatch) { return bindActionCreators({ ...ProductActions, }, dispatch); } export default connect(mapStateToProps, mapDispatchToProps)(Product);
sumber
Saya akan mencoba menjawab pertanyaan asli ...
Komponen Cerdas & Bodoh
Dalam pertanyaan pertama Anda, pada dasarnya Anda bertanya mengapa
bindActionCreators
pada awalnya diperlukan, dan jenis komponen apa yang tidak harus diperhatikan Redux.Singkatnya, idenya di sini adalah bahwa komponen harus dipecah menjadi komponen pintar (wadah) dan bodoh (presentasi). Komponen bodoh bekerja atas dasar kebutuhan untuk mengetahui. Pekerjaan jiwa mereka adalah membuat data yang diberikan ke HTML dan tidak lebih. Mereka seharusnya tidak menyadari cara kerja aplikasi. Mereka dapat dilihat sebagai lapisan kulit bagian depan aplikasi Anda.
Di sisi lain, komponen pintar adalah semacam perekat, yang menyiapkan data untuk komponen bodoh dan lebih disukai tidak melakukan rendering HTML.
Jenis arsitektur ini mempromosikan penggabungan yang longgar antara lapisan UI dan lapisan data di bawahnya. Hal ini pada gilirannya memungkinkan penggantian yang mudah dari salah satu dari dua lapisan dengan yang lain (yaitu desain baru dari UI), yang tidak akan merusak lapisan lainnya.
Untuk menjawab pertanyaan Anda: komponen bodoh seharusnya tidak mengetahui Redux (atau detail implementasi lapisan data yang tidak perlu dalam hal ini) karena kami mungkin ingin menggantinya dengan yang lain di masa mendatang.
Anda dapat menemukan lebih banyak tentang konsep ini di manual Redux dan lebih mendalam dalam artikel Komponen Penyajian dan Kontainer oleh Dan Abramov.
Contoh mana yang lebih baik
Pertanyaan kedua adalah tentang keuntungan / kerugian dari contoh yang diberikan.
Dalam contoh pertama , pembuat tindakan didefinisikan dalam
actionCreators
file / modul terpisah , yang berarti mereka dapat digunakan kembali di tempat lain. Ini adalah cara standar untuk mendefinisikan tindakan. Saya tidak benar-benar melihat kerugian dalam hal ini.Contoh kedua mendefinisikan pembuat tindakan sebaris, yang memiliki banyak kelemahan:
consts
terpisah, sehingga dapat direferensikan dalam reduksi - yang akan mengurangi kemungkinan kesalahan pengetikanContoh kedua memiliki satu keunggulan dibandingkan yang pertama - lebih cepat untuk menulis! Jadi, jika Anda tidak memiliki rencana yang lebih besar untuk kode Anda, itu mungkin baik-baik saja.
Saya harap saya bisa menjelaskan sedikit ...
sumber
Salah satu kegunaan yang mungkin
bindActionCreators()
adalah untuk "memetakan" banyak tindakan bersama-sama sebagai satu prop.Pengiriman normal terlihat seperti ini:
Petakan beberapa tindakan pengguna yang umum ke properti.
const mapStateToProps = (state: IAppState) => { return { // map state here } } const mapDispatchToProps = (dispatch: Dispatch) => { return { userLogin: () => { dispatch(login()); }, userEditEmail: () => { dispatch(editEmail()); }, }; }; export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
Dalam proyek yang lebih besar, memetakan setiap pengiriman secara terpisah dapat terasa berat. Jika kami memiliki banyak tindakan yang terkait satu sama lain, kami dapat menggabungkan tindakan ini . Misalnya file tindakan pengguna yang melakukan semua jenis tindakan terkait pengguna yang berbeda. Alih-alih memanggil setiap tindakan sebagai dispatch terpisah kita dapat menggunakan
bindActionCreators()
bukandispatch
.Beberapa Pengiriman menggunakan bindActionCreators ()
Impor semua tindakan terkait Anda. Semuanya mungkin ada di file yang sama di toko redux
import * as allUserActions from "./store/actions/user";
Dan sekarang alih-alih menggunakan pengiriman, gunakan bindActionCreators ()
const mapDispatchToProps = (dispatch: Dispatch) => { return { ...bindActionCreators(allUserActions, dispatch); }, }; }; export default connect(mapStateToProps, mapDispatchToProps, (stateProps, dispatchProps, ownProps) => { return { ...stateProps, userAction: dispatchProps ownProps, } })(MyComponent);
Sekarang saya dapat menggunakan prop
userAction
untuk memanggil semua tindakan dalam komponen Anda.YAITU:
userAction.login()
userAction.editEmail()
atauthis.props.userAction.login()
this.props.userAction.editEmail()
.CATATAN: Anda tidak perlu memetakan bindActionCreators () ke satu prop. (Tambahan
=> {return {}}
yang memetakan keuserAction
). Anda juga dapat menggunakanbindActionCreators()
untuk memetakan semua tindakan dari satu file sebagai alat peraga terpisah. Tapi menurut saya, melakukan itu bisa membingungkan. Saya lebih suka setiap tindakan atau "kelompok tindakan" diberi nama yang jelas. Saya juga suka menamai theownProps
agar lebih deskriptif tentang apa itu "alat peraga anak" ini atau dari mana asalnya. Saat menggunakan Redux + React, ini bisa menjadi sedikit membingungkan di mana semua properti disediakan sehingga semakin deskriptif semakin baik.sumber
dengan menggunakan
bindActionCreators
, itu dapat mengelompokkan beberapa fungsi tindakan dan meneruskannya ke komponen yang tidak mengetahui Redux (Komponen Dumb) seperti itu// actions.js export const increment = () => ({ type: 'INCREMENT' }) export const decrement = () => ({ type: 'DECREMENT' })
// main.js import { Component } from 'react' import { bindActionCreators } from 'redux' import * as Actions from './actions.js' import Counter from './counter.js' class Main extends Component { constructor(props) { super(props); const { dispatch } = props; this.boundActionCreators = bindActionCreators(Actions, dispatch) } render() { return ( <Counter {...this.boundActionCreators} /> ) } }
// counter.js import { Component } from 'react' export default Counter extends Component { render() { <div> <button onclick={() => this.props.increment()} <button onclick={() => this.props.decrement()} </div> } }
sumber
Saya juga ingin mengetahui lebih banyak tentang bindActionsCreators dan berikut adalah cara saya menerapkannya dalam proyek saya.
// Actions.js // Action Creator const loginRequest = (username, password) => { return { type: 'LOGIN_REQUEST', username, password, } } const logoutRequest = () => { return { type: 'LOGOUT_REQUEST' } } export default { loginRequest, logoutRequest };
Di Komponen React Anda
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import ActionCreators from './actions' class App extends Component { componentDidMount() { // now you can access your action creators from props. this.props.loginRequest('username', 'password'); } render() { return null; } } const mapStateToProps = () => null; const mapDispatchToProps = dispatch => ({ ...bindActionCreators(ActionCreators, dispatch) }); export default connect( mapStateToProps, mapDispatchToProps, )(App);
sumber
Salah satu kasus penggunaan yang bagus
bindActionCreators
adalah untuk integrasi dengan redux-saga menggunakan redux-saga-routine . Sebagai contoh:// routines.js import { createRoutine } from "redux-saga-routines"; export const fetchPosts = createRoutine("FETCH_POSTS");
// Posts.js import React from "react"; import { bindActionCreators } from "redux"; import { connect } from "react-redux"; import { fetchPosts } from "routines"; class Posts extends React.Component { componentDidMount() { const { fetchPosts } = this.props; fetchPosts(); } render() { const { posts } = this.props; return ( <ul> {posts.map((post, i) => ( <li key={i}>{post}</li> ))} </ul> ); } } const mapStateToProps = ({ posts }) => ({ posts }); const mapDispatchToProps = dispatch => ({ ...bindActionCreators({ fetchPosts }, dispatch) }); export default connect( mapStateToProps, mapDispatchToProps )(Posts);
// reducers.js import { fetchPosts } from "routines"; const initialState = []; export const posts = (state = initialState, { type, payload }) => { switch (type) { case fetchPosts.SUCCESS: return payload.data; default: return state; } };
// api.js import axios from "axios"; export const JSON_OPTS = { headers: { Accept: "application/json" } }; export const GET = (url, opts) => axios.get(url, opts).then(({ data, headers }) => ({ data, headers }));
// sagas.js import { GET, JSON_OPTS } from "api"; import { fetchPosts } from "routines"; import { call, put, takeLatest } from "redux-saga/effects"; export function* fetchPostsSaga() { try { yield put(fetchPosts.request()); const { data } = yield call(GET, "/api/posts", JSON_OPTS); yield put(fetchPosts.success(data)); } catch (error) { if (error.response) { const { status, data } = error.response; yield put(fetchPosts.failure({ status, data })); } else { yield put(fetchPosts.failure(error.message)); } } finally { yield put(fetchPosts.fulfill()); } } export function* fetchPostsRequestSaga() { yield takeLatest(fetchPosts.TRIGGER, fetchPostsSaga); }
Perhatikan bahwa pola ini dapat diimplementasikan menggunakan React Hooks (mulai dari React 16.8).
sumber
The docs Pernyataan ini sangat jelas:
Ini jelas merupakan kasus penggunaan yang mungkin muncul dalam satu kondisi berikut dan hanya:
Katakanlah, kami memiliki komponen A dan B:
// A use connect and updates the redux store const A = props => {} export default connect()(A) // B doesn't use connect therefore it does not know about the redux store. const B = props => {} export default B
Menyuntikkan ke react-redux: (A)
const boundActionCreators = bindActionCreators(SomeActionCreator, dispatch) // myActionCreatorMethod, // myActionCreatorMethod2, // myActionCreatorMethod3, // when we want to dispatch const action = SomeActionCreator.myActionCreatorMethod('My updates') dispatch(action)
Disuntikkan oleh react-redux: (B)
const { myActionCreatorMethod } = props <B myActionCreatorMethod={myActionCreatorMethod} {...boundActionCreators} />
Memperhatikan hal-hal berikut?
Kami memperbarui penyimpanan redux melalui komponen A sementara kami tidak mengetahui penyimpanan redux di komponen B.
Kami tidak memperbarui di komponen A. Untuk mengetahui sebenarnya apa yang saya maksud, Anda dapat menjelajahi posting ini . Saya harap Anda punya ide.
sumber