mapDispatchToProps คืออะไร


358

ฉันอ่านเอกสารสำหรับห้องสมุด Redux และมันมีตัวอย่างนี้:

นอกเหนือจากการอ่านสถานะแล้วส่วนประกอบคอนเทนเนอร์ยังสามารถส่งการกระทำได้ ในทำนองเดียวกันคุณสามารถกำหนดฟังก์ชั่นที่เรียกmapDispatchToProps()ว่ารับdispatch()วิธีการและส่งกลับอุปกรณ์ประกอบฉากโทรกลับที่คุณต้องการฉีดเข้าไปในองค์ประกอบการนำเสนอ

จริง ๆ แล้วมันไม่มีเหตุผล ทำไมคุณต้องการmapDispatchToPropsเมื่อคุณมีmapStateToProps?

พวกเขายังให้ตัวอย่างโค้ดที่มีประโยชน์นี้:

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

ใครช่วยอธิบายในแง่ของคนธรรมดาได้ว่าฟังก์ชั่นนี้คืออะไรและทำไมมันถึงมีประโยชน์?

คำตอบ:


577

ฉันรู้สึกเหมือนไม่มีคำตอบใด ๆ ที่ตกผลึกทำไมmapDispatchToPropsมีประโยชน์

นี้สามารถจริงๆเท่านั้นจะตอบในบริบทของcontainer-componentรูปแบบซึ่งผมพบว่าเข้าใจที่ดีที่สุดโดยการอ่านครั้งแรก: ส่วนประกอบตู้คอนเทนเนอร์แล้วการใช้งานที่มีการตอบสนอง

สรุปคุณcomponentsควรจะกังวลเฉพาะกับการแสดงเนื้อหา สถานที่เดียวที่พวกเขาควรจะได้รับข้อมูลจากการเป็นอุปกรณ์ประกอบฉากของพวกเขา

แยกจาก "การแสดงเนื้อหา" (ส่วนประกอบ) คือ:

  • วิธีที่คุณนำสิ่งของมาแสดง
  • และวิธีจัดการกับเหตุการณ์ต่างๆ

นั่นคือสิ่งที่containersมีไว้เพื่อ

ดังนั้น "การออกแบบที่ดี" componentในรูปแบบมีลักษณะดังนี้:

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

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

ดูวิธีการส่วนนี้ได้รับข้อมูลก็จะแสดงจากอุปกรณ์ประกอบฉาก (ซึ่งมาจากการจัดเก็บ Redux ผ่านmapStateToProps) sendTheAlert()และยังได้รับฟังก์ชั่นการกระทำของตนจากอุปกรณ์ประกอบฉากที่:

นั่นคือสิ่งที่mapDispatchToPropsมา: ในที่สอดคล้องกันcontainer

// 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
)

ฉันสงสัยว่าคุณสามารถเห็นว่าตอนนี้มันเป็นcontainer 1ที่รู้เกี่ยวกับการดัดแปลงและการจัดส่งและการจัดเก็บและรัฐและสิ่งที่ ...

componentในรูปแบบFancyAlerterซึ่งจะแสดงผลไม่จำเป็นต้องรู้เกี่ยวกับการใด ๆ ของสิ่งที่มันได้รับวิธีการของการเรียกร้องที่onClickปุ่มผ่านทางอุปกรณ์ประกอบฉากของมัน

และ ... mapDispatchToPropsเป็นวิธีที่มีประโยชน์ที่ redux จัดเตรียมเพื่อให้คอนเทนเนอร์ส่งผ่านฟังก์ชันนั้นไปยังส่วนประกอบที่ถูกห่อบนอุปกรณ์ประกอบฉากได้อย่างง่ายดาย

ทุกลักษณะนี้มากเช่นตัวอย่างเช่นสิ่งที่ต้องทำในเอกสารและคำตอบอื่นที่นี่ แต่ผมได้พยายามที่จะโยนมันทิ้งเสียในแง่ของรูปแบบที่จะเน้นว่าทำไม

(หมายเหตุ: คุณไม่สามารถใช้mapStateToPropsเพื่อจุดประสงค์เดียวmapDispatchToPropsกับเหตุผลพื้นฐานที่คุณไม่สามารถเข้าถึงdispatchภายในmapStateToPropได้ดังนั้นคุณจึงไม่สามารถใช้mapStateToPropsวิธีที่ส่วนประกอบที่ห่อไว้dispatchได้

ฉันไม่รู้ว่าทำไมพวกเขาเลือกที่จะแบ่งมันออกเป็นสองฟังก์ชั่นการทำแผนที่ - มันอาจจะเป็นเรื่องที่ยุ่งยากกว่าที่จะมีmapToProps(state, dispatch, props) IE หนึ่งฟังก์ชั่นที่จะทำทั้งสองอย่าง!


1 โปรดทราบว่าฉันตั้งใจตั้งชื่อคอนเทนเนอร์อย่างชัดเจนFancyButtonContainerเพื่อเน้นว่ามันเป็น "สิ่ง" - ตัวตน (และการมีอยู่จริง!) ของคอนเทนเนอร์เป็น "สิ่ง" บางครั้งก็หายไปในชวเลข

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

ไวยากรณ์ที่แสดงในตัวอย่างส่วนใหญ่


5
ฉันยังต้องการที่จะรู้: สิ่งที่เกี่ยวกับฟังก์ชั่นที่ต้องการไม่สามารถจัดการได้โดยการเรียกโดยตรง store.dispatch จากภายในองค์ประกอบ?
pixelpax

8
@ user2130130 ไม่มี มันเกี่ยวกับการออกแบบที่ดี หากคุณเชื่อมโยงส่วนประกอบของคุณกับ store.dispatch ดังนั้นเมื่อคุณตัดสินใจที่จะแยกปัจจัยออกจาก redux หรือต้องการใช้งานบางที่ที่ไม่ได้ใช้ redxu (หรือสิ่งอื่น ๆ ที่ฉันไม่คิดตอนนี้) คุณติดอยู่กับ มีการเปลี่ยนแปลงมากมาย คำถามของคุณพูดถึง "ทำไมเราถึงใส่ใจกับ 'แนวทางปฏิบัติที่ดีในการออกแบบ' คุณจะได้รับฟังก์ชั่นการทำงานเดียวกัน mapDispatchToProps มีให้เพื่อให้คุณสามารถเขียนส่วนประกอบที่ออกแบบมาอย่างดีแยกส่วนประกอบอย่างหมดจด
GreenAsJade

4
สิ่งที่ฉันไม่ได้มาที่นี่จริงๆคืออะไร: ALERT_ACTIONนั่นคือฟังก์ชั่นการกระทำหรือtypeที่ถูกส่งกลับจากฟังก์ชั่นการกระทำ? : / งงงวยมาก
Jamie Hutber

1
@JamieHutber อย่างเคร่งครัด ALERT_ACTION ไม่มีส่วนเกี่ยวข้องกับคำถามนี้ มันเป็นอาร์กิวเมนต์ที่ถูกต้องในการจัดส่งและในขณะที่มันเกิดขึ้นในรหัสของฉันมันมาจาก "ตัวสร้างการกระทำ" ซึ่งส่งคืนวัตถุที่ใช้การจัดส่งตามที่อธิบายไว้redux.js.org/docs/api/Store.html#dispatch . จุดหลักที่นี่คือวิธีการโทรส่งอธิบายไว้ในภาชนะบรรจุและส่งผ่านไปยังอุปกรณ์ประกอบฉาก ส่วนประกอบได้รับฟังก์ชั่นจากอุปกรณ์ประกอบฉากเท่านั้นไม่มีที่อื่น วิธีที่ "ผิด" ในการทำมันในรูปแบบนี้คือการส่งการส่งไปยังส่วนประกอบและทำการโทรเดียวกันนั้นในองค์ประกอบ
GreenAsJade

1
หากคุณมีผู้สร้างแอ็คชั่นหลายตัวที่ต้องส่งผ่านไปยังองค์ประกอบย่อยเป็นอุปกรณ์ประกอบฉากอีกทางเลือกหนึ่งคือห่อพวกเขาด้วย bindActionCreators ภายใน mapDispatchToProps (ดูredux.js.org/docs/api/bindActionCreators.html ); อีกทางเลือกหนึ่งคือให้วัตถุของผู้สร้างแอคชั่นเพื่อเชื่อมต่อ () เช่นเชื่อมต่อ (mapStateToProps, {actioncreators}), react-redux จะตัดคำเหล่านั้นด้วย dispatch () สำหรับคุณ
dave

81

มันเป็นชวเลข ดังนั้นแทนที่จะต้องเขียน:

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

คุณจะใช้ mapDispatchToProps ตามที่แสดงในโค้ดตัวอย่างของคุณแล้วเขียนที่อื่น:

this.props.onTodoClick(id);

หรือมีโอกาสมากขึ้นในกรณีนี้คุณมีตัวจัดการเหตุการณ์:

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

มีวิดีโอที่เป็นประโยชน์โดย Dan Abramov ที่นี่: https://egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist


ขอบคุณ. ฉันยังสงสัยว่าการเพิ่มการจัดส่งไปยังอุปกรณ์ประกอบฉากในตอนแรกเป็นอย่างไร
รหัส Whisperer

14
หากคุณไม่มีmapDispatchฟังก์ชั่นของคุณเองRedux จะใช้ค่าเริ่มต้น เริ่มต้นที่mapDispatchฟังก์ชั่นเพียงแค่เตะอ้างอิงฟังก์ชั่นและให้มันให้คุณเป็นdispatch this.props.dispatch
markerikson

7
วิธีการจัดส่งถูกส่งผ่านโดยองค์ประกอบของผู้ให้บริการ
Diego Haz

55

mapStateToProps()เป็นยูทิลิตี้ที่ช่วยให้องค์ประกอบของคุณได้รับสถานะอัปเดต (ซึ่งมีการอัปเดตโดยส่วนประกอบอื่น ๆ )
mapDispatchToProps()เป็นยูทิลิตี้ที่จะช่วยให้องค์ประกอบของคุณเริ่มเหตุการณ์การกระทำ


23

mapStateToProps, mapDispatchToPropsและconnectจากreact-reduxห้องสมุดให้เป็นวิธีที่สะดวกในการเข้าถึงของคุณstateและdispatchฟังก์ชั่นของร้านค้าของคุณ ดังนั้นโดยทั่วไปแล้วการเชื่อมต่อคือองค์ประกอบการสั่งซื้อที่สูงขึ้นคุณยังสามารถคิดว่าเป็นเสื้อคลุมถ้าสิ่งนี้เหมาะสมสำหรับคุณ ดังนั้นทุกครั้งที่stateมีการเปลี่ยนแปลงของคุณmapStateToPropsจะถูกเรียกด้วยใหม่ของคุณstateและต่อมาเมื่อคุณpropsอัปเดตองค์ประกอบจะเรียกใช้ฟังก์ชั่นการแสดงผลเพื่อแสดงองค์ประกอบของคุณในเบราว์เซอร์ mapDispatchToPropsเก็บคีย์ - ค่าไว้ที่propsองค์ประกอบของคุณโดยปกติจะอยู่ในรูปแบบของฟังก์ชั่น ในลักษณะดังกล่าวที่คุณสามารถเรียกstateการเปลี่ยนแปลงจากคอมโพเนนท์onClick, onChangeเหตุการณ์ที่เกิดขึ้น

จากเอกสาร:

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) 

นอกจากนี้ตรวจสอบให้แน่ใจว่าคุณคุ้นเคยกับฟังก์ชั่นการตอบสนองไร้สัญชาติและส่วนประกอบที่สูงกว่า


ดังนั้นการจัดส่งเป็นเหมือนเหตุการณ์โดยทั่วไปหรือไม่
รหัส Whisperer

2
มันอาจจะเกี่ยวข้องกับเหตุการณ์การจัดส่งเป็นเพียงฟังก์ชั่นและวิธีเดียวที่จะเปลี่ยนสถานะแอปพลิเคชันของคุณ mapStateToPropsเป็นวิธีหนึ่งในการแสดงฟังก์ชั่นการจัดส่งของร้านค้าของคุณไปยัง React Component นอกจากนี้ทราบว่าการเชื่อมต่อไม่ได้เป็นส่วนหนึ่งของการดัดแปลงในความเป็นจริงมันเป็นเพียงสาธารณูปโภคและสำเร็จรูปลดห้องสมุดเรียกว่าตอบสนอง-Reduxที่จะทำงานร่วมกับตอบสนองและ Redux คุณสามารถบรรลุผลลัพธ์เดียวกันโดยไม่ต้องทำปฏิกิริยา -uxux ถ้าคุณผ่านร้านค้าของคุณจากองค์ประกอบปฏิกิริยารากสาดไปยังเด็ก ๆ
Vlad Filimon

3

mapStateToPropsได้รับstateและpropsและช่วยให้คุณสามารถดึงอุปกรณ์ประกอบฉากจากรัฐเพื่อส่งผ่านไปยังส่วนประกอบ

mapDispatchToPropsรับdispatchและpropsและมีไว้สำหรับคุณในการผูกผู้สร้างแอ็คชั่นเพื่อจัดส่งดังนั้นเมื่อคุณเรียกใช้ฟังก์ชันผลลัพธ์ที่ได้รับ

ฉันพบว่าสิ่งนี้ช่วยให้คุณไม่ต้องทำอะไรdispatch(actionCreator())ในองค์ประกอบของคุณจึงทำให้อ่านง่ายขึ้น

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


ขอบคุณ แต่ค่าของdispatchวิธีการคืออะไร? มันมาจากไหน?
รหัส Whisperer

โอ้ การแจกจ่ายโดยทั่วไปทำให้การดำเนินการเริ่มต้นการไหลของ redux / flux ทิศทางเดียว คำตอบอื่น ๆ ดูเหมือนจะตอบคำถามของคุณดีกว่านี้
Harry Moreno

นอกจากนี้วิธีการจัดส่งยังมาจากการปรับปรุงโดย<Provider/>ตัวมันเอง มันทำตามคำสั่งมายากลของตัวเองเพื่อที่จะรับประกันว่าการส่งนั้นมีอยู่ในส่วนประกอบของลูก
Ricardo Magalhães

3

ตอนนี้สมมติว่ามีการดำเนินการสำหรับ redux ดังนี้:

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

เมื่อคุณนำเข้า

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);

ตามชื่อฟังก์ชั่นบอกว่าmapDispatchToProps()แผนที่dispatchการกระทำเพื่อประกอบฉาก (อุปกรณ์ประกอบฉากของเราส่วนประกอบ)

ดังนั้นเสาonTodoClickเป็นกุญแจสำคัญในการทำงานที่ได้รับมอบหมายให้ดำเนินการmapDispatchToProps furthere จัดส่งaddTodo

นอกจากนี้หากคุณต้องการตัดรหัสและเลี่ยงการใช้งานด้วยตนเองคุณสามารถทำได้

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);

ซึ่งหมายความว่า

const mapDispatchToProps = dispatch => {
    return {
      addTodo: () => { 
        dispatch(addTodo())
      }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.