Co to jest mapDispatchToProps?

358

Czytałem dokumentację biblioteki Redux i ma ona ten przykład:

Oprócz odczytu stanu komponenty kontenera mogą wywoływać akcje. W podobny sposób można zdefiniować funkcję o nazwie, mapDispatchToProps()która odbiera dispatch()metodę i zwraca rekwizyty wywołania zwrotnego, które chcesz wstrzyknąć do komponentu prezentacji.

To właściwie nie ma sensu. Dlaczego potrzebujesz, mapDispatchToPropsskoro już masz mapStateToProps?

Udostępniają również przydatny przykładowy kod:

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

Czy ktoś może wyjaśnić laikowi, czym jest ta funkcja i dlaczego jest przydatna?

Zaklinacz kodów
źródło

Odpowiedzi:

577

Wydaje mi się, że żadna z odpowiedzi nie ukazuje, dlaczego mapDispatchToPropsjest przydatna.

Naprawdę można na to odpowiedzieć tylko w kontekście container-componentwzorca, który najlepiej zrozumiałem w pierwszym czytaniu: Składniki kontenera, a następnie użycie z React .

W skrócie, componentspowinieneś zajmować się tylko wyświetlaniem rzeczy. Jedyne miejsce oni mają dostać informację z jest ich rekwizyty .

Od „wyświetlania rzeczy” (komponentów) oddzielone jest:

  • w jaki sposób wyświetlasz rzeczy,
  • i jak radzisz sobie ze zdarzeniami.

Po to containerssą.

Dlatego „dobrze zaprojektowany” componentwzór wygląda następująco:

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

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

Zobacz, w jaki sposób ten komponent pobiera informacje, które wyświetla z rekwizytów (które pochodzą ze sklepu redux przez mapStateToProps), a także pobiera swoją funkcję akcji ze swoich rekwizytów:sendTheAlert() .

Tam właśnie mapDispatchToPropsprzychodzi: w odpowiednimcontainer

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

Zastanawiam się, czy widzisz, teraz, gdy jest to container 1 który wie o redux i wysyłce oraz o przechowywaniu, stanie i ... rzeczach.

componentWe wzorcu, FancyAlerter, co robi renderowania nie musi wiedzieć o żadnej z tych rzeczy: to dostaje swoją metodę na wywołanieonClick przycisku, za pośrednictwem swoich rekwizytów.

I ... mapDispatchToProps był użytecznym środkiem, który zapewnia redux, aby umożliwić kontenerowi łatwe przekazanie tej funkcji do owiniętego komponentu na jego rekwizytach.

Wszystko to bardzo przypomina przykład todo w dokumentach i kolejną odpowiedź tutaj, ale próbowałem rzucić go w świetle wzoru, aby podkreślić, dlaczego .

(Uwaga: nie można używać mapStateToPropsdo tego samego celu, co mapDispatchToPropsz podstawowego powodu, dla którego nie masz dostępu do dispatchwnętrza mapStateToProp. Nie można więc użyć mapStateToPropszapakowanego komponentu do metody, która używa dispatch.

Nie wiem, dlaczego zdecydowali się podzielić go na dwie funkcje mapowania - być może łatwiej byłoby mieć mapToProps(state, dispatch, props) jedną funkcję IE do obu!


1 Zauważ, że celowo wyraźnie nadałem nazwę kontenerowi FancyButtonContainer, aby podkreślić, że jest to „rzecz” - tożsamość (a zatem i istnienie!) Kontenera jako „rzecz” jest czasami gubiona w skrócie

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

składnia pokazana w większości przykładów

GreenAsJade
źródło
5
Wciąż chciałbym wiedzieć: Co z wymaganą funkcjonalnością nie można było obsłużyć, wywołując bezpośrednio store.dispatch z poziomu komponentu?
pixelpax
8
@ user2130130 Brak. Chodzi o dobry design. Jeśli podłączyłeś swój komponent do store.dispatch, to kiedy zdecydujesz się odrzucić redux lub zechcesz go użyć w miejscu, które nie jest oparte na redxu (lub innej rzeczy, o której nie mogę teraz myśleć), utkniesz z dużo zmian. Twoje pytanie uogólnia na „dlaczego zawracamy sobie głowę„ dobrymi praktykami projektowymi ”- otrzymujesz taką samą funkcjonalność, jak ją kodujesz”. Dzięki mapDispatchToProps możesz pisać dobrze zaprojektowane, czysto oddzielone komponenty.
GreenAsJade
4
To, czego tak naprawdę nie rozumiem, to: ALERT_ACTIONczy to funkcja akcji, czy ta, typektóra jest zwracana z funkcji akcji? : / so baffed
Jamie Hutber
1
@JamieHutber Ściśle, ALERT_ACTION nie ma nic wspólnego z tym pytaniem. Jest to poprawny argument do wysłania, a tak się składa, że ​​w moim kodzie pochodzi on z „konstruktora akcji”, który zwraca obiekt, z którego korzysta dispatch, jak opisano redux.js.org/docs/api/Store.html#dispatch . Najważniejsze jest to, że sposób wywołania wysyłki jest opisany w kontenerze i przekazany na rekwizyty komponentów. Komponent pobiera funkcje tylko ze swoich rekwizytów, nigdzie indziej. „Nieprawidłowym” sposobem wykonania tego w tym schemacie byłoby przekazanie wysyłki do komponentu i wykonanie tego samego wywołania w komponencie.
GreenAsJade
1
Jeśli masz wielu twórców akcji, które muszą zostać przekazane do komponentu podrzędnego jako rekwizyty, jedną z możliwości jest zawinięcie ich w bindActionCreators wewnątrz mapDispatchToProps (patrz redux.js.org/docs/api/bindActionCreators.html ); Inną alternatywą jest po prostu udostępnienie obiektu twórców akcji dla connect (), np. connect (mapStateToProps, {actioncreators}), React-Redux opakowuje je za pomocą dispatch ().
dave
81

Zasadniczo jest to skrót. Zamiast więc pisać:

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

Używałbyś mapDispatchToProps, jak pokazano w przykładowym kodzie, a następnie w innym miejscu napisz:

this.props.onTodoClick(id);

lub bardziej prawdopodobne, że w tym przypadku będziesz mieć to jako moduł obsługi zdarzeń:

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

Tutaj znajduje się pomocne wideo Dana Abramova: https://egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist

hamstu
źródło
Dziękuję Ci. Zastanawiam się także, w jaki sposób w pierwszej kolejności dodaje się wysyłkę do rekwizytów?
Code Whisperer
14
Jeśli nie zapewnisz własnej mapDispatchfunkcji, Redux użyje domyślnej. Ta domyślna mapDispatchfunkcja po prostu pobiera dispatchodwołanie do funkcji i daje ci ją jako this.props.dispatch.
markerikson
7
Metodę wysyłki przekazuje Component Provider
Diego Haz
55

mapStateToProps()to narzędzie, które pomaga Twojemu komponentowi zaktualizować stan (który jest aktualizowany przez niektóre inne komponenty),
mapDispatchToProps()to narzędzie, które pomoże Twojemu komponentowi uruchomić zdarzenie akcji (akcja wywołująca, która może spowodować zmianę stanu aplikacji)

Saisurya Kattamuri
źródło
23

mapStateToProps, mapDispatchToPropsa connectz react-reduxbiblioteki zapewnia wygodny sposób na dostęp do twojego sklepu statei jego dispatchfunkcji. Więc w zasadzie connect jest składnikiem wyższego rzędu, możesz również pomyśleć jako opakowanie, jeśli ma to dla Ciebie sens. Tak więc przy każdej statezmianie twoja mapStateToPropsbędzie wywoływana z nowym, statea następnie podczas propsaktualizacji komponent uruchomi funkcję renderowania, aby renderować komponent w przeglądarce. mapDispatchToPropsprzechowuje również kluczowe wartości w propstwoim komponencie, zwykle przyjmują one postać funkcji. W ten sposób możesz wywołać statezmianę ze swojego komponentu onClick, onChangezdarzeń.

Z dokumentów:

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) 

Upewnij się także, że znasz React bezpaństwowe funkcje i komponenty wyższego rzędu

Vlad Filimon
źródło
Więc wysyłka jest jak wydarzenie w zasadzie?
Code Whisperer
2
Może to być związane ze zdarzeniem, wysyłka jest tylko funkcją i jedynym sposobem na zmianę stanu aplikacji . mapStateToProps to jeden ze sposobów na ujawnienie funkcji wysyłki Twojego sklepu React Component. Zauważ też, że connect nie jest częścią redux, w rzeczywistości jest to tylko narzędzie i biblioteka redukująca płytkę zwaną React-Redux do pracy z React i Redux. Możesz osiągnąć ten sam wynik bez reakcji-redux, jeśli przekażesz swój sklep z głównego składnika reagowania na dzieci.
Vlad Filimon,
3

mapStateToPropsotrzymuje stateiprops i pozwala wyodrębnić rekwizyty ze stanu przejść do komponentu.

mapDispatchToPropsotrzymuje dispatchi propssłuży do wiązania twórców akcji do wysłania, więc po wykonaniu wynikowej funkcji akcja zostaje wysłana.

Uważam, że to tylko ratuje cię przed koniecznością zrobienia tego dispatch(actionCreator()) w komponencie, dzięki czemu jest nieco łatwiejszy do odczytania.

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

Harry Moreno
źródło
Dziękuję, ale jaka jest wartość tej dispatchmetody? Skąd to pochodzi?
Code Whisperer
O. Wysłanie powoduje, że akcja rozpoczyna przepływ jednokierunkowy redux / flux. Wydaje się, że inne odpowiedzi odpowiedziały na twoje pytanie lepiej niż to.
Harry Moreno,
Ponadto metoda wysyłki pochodzi z samego rozszerzenia <Provider/>. Wykonuje własną magię komponentów wysokiego rzędu, aby zagwarantować, że wysyłka jest dostępna w jej komponentach potomnych.
Ricardo Magalhães
3

Załóżmy teraz, że istnieje akcja redux, ponieważ:

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

Kiedy go zaimportujesz,

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

Jak sama nazwa funkcji mówi mapDispatchToProps(), mapdispatch akcję na rekwizyty (rekwizyty naszego komponentu)

Więc prop onTodoClickjest kluczem do mapDispatchToPropsfunkcji, która przekazuje dalej do wysłania akcji addTodo.

Również jeśli chcesz przyciąć kod i ominąć ręczną implementację, możesz to zrobić,

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

Co dokładnie znaczy

const mapDispatchToProps = dispatch => {
    return {
      addTodo: () => { 
        dispatch(addTodo())
      }
    }
}
Poznaj Zaveri
źródło