MapDispatchToProps là gì?


358

Tôi đã đọc tài liệu cho thư viện Redux và nó có ví dụ này:

Ngoài việc đọc trạng thái, các thành phần container có thể gửi các hành động. Theo cách tương tự, bạn có thể định nghĩa một hàm được gọi là mapDispatchToProps()nhận dispatch()phương thức và trả về các đạo cụ gọi lại mà bạn muốn đưa vào thành phần trình bày.

Điều này thực sự không có ý nghĩa. Tại sao bạn cần mapDispatchToPropskhi bạn đã có mapStateToProps?

Họ cũng cung cấp mẫu mã tiện dụng này:

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

Ai đó có thể vui lòng giải thích trong điều khoản của giáo dân về chức năng này là gì và tại sao nó hữu ích?

Câu trả lời:


577

Tôi cảm thấy như không có câu trả lời nào kết tinh tại sao lại mapDispatchToPropshữu ích.

Điều này thực sự chỉ có thể được trả lời trong ngữ cảnh của container-componentmẫu mà tôi thấy rõ nhất khi đọc lần đầu: Thành phần Container sau đó là Cách sử dụng với React .

Tóm lại, bạn componentsđược cho là chỉ quan tâm đến việc hiển thị nội dung. Nơi duy nhất họ có nghĩa vụ phải lấy thông tin là đạo cụ của họ .

Tách từ "hiển thị công cụ" (thành phần) là:

  • làm thế nào bạn có được những thứ để hiển thị,
  • và cách bạn xử lý các sự kiện.

Đó là những gì containersdành cho.

Do đó, một "thiết kế tốt" componenttrong mẫu trông như thế này:

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

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

Xem cách thành phần này nhận thông tin mà nó hiển thị từ các đạo cụ (xuất phát từ cửa hàng redux thông qua mapStateToProps) và nó cũng có chức năng hành động từ các đạo cụ của nó : sendTheAlert().

Đó là nơi mapDispatchToPropsđến: trong tương ứngcontainer

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

Tôi tự hỏi nếu bạn có thể nhìn thấy, bây giờ đó là container 1 người biết về redux, công văn và lưu trữ và trạng thái và ... công cụ.

Trong componentmẫu, FancyAlerterkết xuất đồ họa không cần biết về bất kỳ thứ gì trong số đó: nó có phương thức gọi onClicknút, thông qua các đạo cụ của nó.

Và ... mapDispatchToPropslà phương tiện hữu ích mà redux cung cấp để cho phép container dễ dàng chuyển chức năng đó vào thành phần được bọc trên các đạo cụ của nó.

Tất cả điều này trông rất giống ví dụ việc cần làm trong tài liệu, và một câu trả lời khác ở đây, nhưng tôi đã cố gắng đưa nó ra dưới ánh sáng của mẫu để nhấn mạnh lý do tại sao .

(Lưu ý: bạn không thể sử dụng mapStateToPropscho cùng mục đích vì mapDispatchToPropslý do cơ bản là bạn không có quyền truy cập vào dispatchbên trong mapStateToProp. Vì vậy, bạn không thể sử dụng mapStateToPropsđể cung cấp cho thành phần được bao bọc một phương thức sử dụng dispatch.

Tôi không biết lý do tại sao họ chọn chia nó thành hai chức năng ánh xạ - có thể đã gọn gàng hơn khi có mapToProps(state, dispatch, props) một chức năng IE để thực hiện cả hai!


1 Lưu ý rằng tôi cố tình đặt tên cho container một cách rõ ràng FancyButtonContainer, để làm nổi bật rằng đó là một "vật" - danh tính (và do đó tồn tại!) Của container là "một vật" đôi khi bị mất trong tốc ký

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

cú pháp được hiển thị trong hầu hết các ví dụ


5
Tôi vẫn muốn biết: Điều gì về chức năng cần thiết không thể được xử lý bằng cách gọi trực tiếp store.dispatch từ trong một thành phần?
pixelpax

8
@ user2130130 Không có. Đó là về thiết kế tốt. Nếu bạn đã kết hợp thành phần của mình với store.dispatch, thì khi bạn quyết định loại bỏ redux hoặc muốn sử dụng nó ở một nơi không dựa trên redxu (hoặc một số điều khác tôi không thể nghĩ ra bây giờ), bạn sẽ bị mắc kẹt với rất nhiều thay đổi. Câu hỏi của bạn khái quát đến "tại sao chúng tôi bận tâm với 'thực tiễn thiết kế tốt' - bạn có được chức năng tương tự tuy nhiên bạn mã hóa nó". mapDispatchToProps được cung cấp để bạn có thể viết các thành phần được tách rời được thiết kế tốt.
GreenAsJade

4
Điều tôi thực sự không nhận được ở đây là: ALERT_ACTIONchức năng hành động hay chức năng typeđược trả về từ chức năng hành động? : / quá bối rối
Jamie Hutber

1
@JamieHutber Nghiêm túc, ALERT_ACTION không liên quan gì đến câu hỏi này. Đó là một đối số hợp lệ để gửi đi và như nó xảy ra, trong mã của tôi, nó xuất phát từ một "trình xây dựng hành động", trả về một đối tượng mà công văn sử dụng, như được mô tả redux.js.org/docs/api/Store.html#dispatch . Điểm chính ở đây là làm thế nào để gọi công văn được mô tả trong container và được truyền vào các đạo cụ thành phần. Thành phần này chỉ có chức năng từ các đạo cụ của nó, không ở đâu khác. Cách thực hiện "sai" trong mẫu này sẽ là chuyển công văn đến thành phần và thực hiện cuộc gọi tương tự trong thành phần đó.
GreenAsJade

1
Nếu bạn có nhiều trình tạo hành động cần được truyền cho thành phần con làm đạo cụ, một cách khác là bọc chúng bằng bindActionCreators bên trong mapDispatchToProps (xem redux.js.org/docs/api/bindActionCreators.html ); một cách khác là chỉ đơn giản là cung cấp một đối tượng của người tạo hành động để kết nối (), ví dụ: kết nối (mapStateToProps, {actioncreators}), Reac-redux sẽ bọc chúng bằng công văn () cho bạn.
dave

81

Về cơ bản nó là một tốc ký. Vì vậy, thay vì phải viết:

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

Bạn sẽ sử dụng mapDispatchToProps như được hiển thị trong mã ví dụ của bạn và sau đó viết ở nơi khác:

this.props.onTodoClick(id);

hoặc nhiều khả năng trong trường hợp này, bạn sẽ có điều đó với tư cách là người xử lý sự kiện:

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

Có một video hữu ích của Dan Abramov về điều này tại đây: https://egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist


Cảm ơn bạn. Tôi cũng tự hỏi, làm thế nào để công văn được thêm vào đạo cụ ở nơi đầu tiên?
Code Whisperer

14
Nếu bạn không cung cấp mapDispatchchức năng của riêng mình , Redux sẽ sử dụng mặc định. mapDispatchHàm mặc định đó chỉ đơn giản là lấy dispatchtham chiếu hàm và cung cấp cho bạn dưới dạng this.props.dispatch.
Markerikson

7
Phương thức điều phối được truyền lại bởi Thành phần nhà cung cấp
Diego Haz

55

mapStateToProps()là một tiện ích giúp thành phần của bạn có được trạng thái cập nhật (được cập nhật bởi một số thành phần khác),
mapDispatchToProps()là tiện ích giúp thành phần của bạn kích hoạt sự kiện hành động (gửi hành động có thể gây thay đổi trạng thái ứng dụng)


23

mapStateToProps, mapDispatchToPropsconnecttừ react-reduxthư viện cung cấp một cách thuận tiện để truy cập của bạn statedispatchchức năng của cửa hàng của bạn. Vì vậy, về cơ bản kết nối là một thành phần bậc cao hơn, bạn cũng có thể nghĩ như một trình bao bọc nếu điều này có ý nghĩa với bạn. Vì vậy, mỗi khi statethay đổi của bạn mapStateToPropssẽ được gọi với mới statevà sau đó khi bạn propscập nhật thành phần sẽ chạy chức năng kết xuất để kết xuất thành phần của bạn trong trình duyệt. mapDispatchToPropscũng lưu trữ các giá trị khóa trên propsthành phần của bạn, thông thường chúng có dạng hàm. Theo cách đó, bạn có thể kích hoạt statethay đổi từ thành phần onClick, onChangesự kiện của bạn .

Từ tài liệu:

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) 

Đồng thời đảm bảo rằng bạn đã quen thuộc với các hàm không trạng thái Reactcác thành phần bậc cao


Vì vậy, công văn giống như sự kiện về cơ bản?
Code Whisperer

2
Nó có thể liên quan đến sự kiện, công văn chỉ là một chức năng và cách duy nhất để thay đổi trạng thái ứng dụng của bạn . mapStateToProps là một cách để hiển thị chức năng điều phối của cửa hàng của bạn tới Thành phần Phản ứng. Cũng lưu ý rằng kết nối không phải là một phần của redux trong thực tế, nó chỉ là một tiện ích và thư viện rút gọn được gọi là Reac-redux để hoạt động với phản ứng và redux. Bạn có thể đạt được kết quả tương tự mà không cần phản ứng-redux nếu bạn chuyển cửa hàng của mình từ thành phần phản ứng gốc cho trẻ em.
Vlad Filimon

3

mapStateToPropsnhận statepropsvà cho phép bạn trích xuất đạo cụ từ trạng thái để chuyển đến thành phần.

mapDispatchToPropsnhận dispatchpropscó nghĩa là để bạn ràng buộc người tạo hành động gửi đi để khi bạn thực thi chức năng kết quả, hành động sẽ được gửi đi.

Tôi thấy điều này chỉ giúp bạn không phải làm dispatch(actionCreator())trong thành phần của mình, do đó làm cho nó dễ đọc hơn một chút.

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


Cảm ơn bạn nhưng giá trị của dispatchphương pháp là gì? Nó đến từ đâu?
Code Whisperer

Oh. Phân phối về cơ bản làm cho hành động bắt đầu dòng chảy một chiều redux / flux. Các câu trả lời khác dường như đã trả lời câu hỏi của bạn tốt hơn thế này.
Harry Moreno

Ngoài ra, phương thức công văn đến từ sự tăng cường được cung cấp bởi <Provider/>chính nó. Nó thực hiện phép thuật thành phần bậc cao của riêng mình để đảm bảo rằng công văn có sẵn trong các thành phần con của nó.
Ricardo Magalhães

3

Bây giờ giả sử có một hành động cho redux như:

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

Khi bạn nhập nó,

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

Như tên hàm mapDispatchToProps(), bản đồdispatch hành động tới đạo cụ (đạo cụ thành phần của chúng tôi)

Vì vậy, prop onTodoClicklà một chìa khóa để mapDispatchToPropshoạt động mà đại biểu tiếp tục gửi hành động addTodo.

Ngoài ra nếu bạn muốn cắt mã và bỏ qua việc thực hiện thủ công, thì bạn có thể làm điều này,

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

Nghĩa là chính xác

const mapDispatchToProps = dispatch => {
    return {
      addTodo: () => { 
        dispatch(addTodo())
      }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.