score:3

Accepted answer

you have too many questions and how hard we try to explain it what is going on here probably confuses you more. i strongly advise you to watch those two videos from the creator of redux:

getting started with redux and idiomatic redux

those vidoes explain what is redux, how does its pieces get together. so, before following any other tutorials first grasp redux itself.

also, redux's official documentation is great, if you follow it alongside with the videos would be great for your study.

but, let me answer your questions anyway.

first question

the parts that i don't understand are this:

connect(mapstatetoprops, mapdispatchtoprops)(booklist)

what is going on? is this part responsible for making the state and the dispatch method available to the component booklist?

answer

connect here is provided by react-redux package, not redux itself. it is a helper higher order function used to open your state and action creators to your components. so, you guessed right. this is how people generally connect their components into the store to get state and dispatch (to use action creators).

second question

function mapdispatchtoprops(dispatch) {
  // whenver selectbook is called, the result should be passed to all of the reducers.
  // selectbook value is an actioncreator, a function.
  return bindactioncreators({ selectbook: selectbook }, dispatch)
}

are these built in redux functions? what are they returning? what is going on? what is dispatch?

the value selectbook on the right side is a function right? so i guess it gets called, and the return value will flow through the reducers via the dispatch method? but then what is bindactioncreators doing?

how are props made available inside the component booklist?

answer

no, they are not built in redux functions as i explained in the first answer. mapstatetoprops opens your state to your component and feed it as props. so, if you open any state to your component with connect and mapstatetoprops you get this state as props. in your example you get the books state from your global state and open this as books to your component. then this component gets this as this.props.books.

mapdispatchtoprops opens your action creator functions to your component as props. there a couple of ways using this, bindactioncreators is one of them but actually you don't need it here. it is good for getting state if you need it while you are dispatching or passing your action creators to a child component which does not aware of redux. so, bindactioncreators is not a good start to understand mapdispatchtoprops.

basically it is like that:

const mapdispatchtoprops = dispatch => ({
  somefunction: () => dispatch(somefunction())
})

here you are opening your somefunction() action creator to your component as the name somefunction. you can use a different name or you can do other staff here and then dispatch your action creator according to this. but in this example you are not doing anything extra, just dispatching the action creator. so, there is a shorthand for this:

const mapdispatchtoprops = {
    somefunction,
}

yes, for this situation this does the same thing. even, there is a shorter one:

connect(mapstatetoprops, {somefunction})(component)

without using a mapdispatchtoprops you can use your action creators like this, then get as props in your components.

also (yes there is more :)) event without using any function argument in connect, we can use action creators.

connect()(component)
connect(mapstatetoprops)(component)

if we skip mapdispatchtoprops like one of the methods above, dispatch is automatically passed to the component props. then, we can use it like any other prop to dispatch our action creator:

this.props.dispatch(somefunction())

for your example it goes like this (i know this app, so i'm using real action creator example here).

you can write mapdispatchtoprops like this:

const mapdispatchtoprops = dispatch => ( {
  selectbook: book => dispatch( selectbook( book ) ),
} );

here you use selectbook as this.props.selectbook in your component and dispatch an action. you see actually your prop fires a function and it dispatches your real action creator here. remember, action creators returns objects and those objects need to be dispatched in order to go through reducers. so, you are dispatching your action creator (which is returned by selectbook.

now, with bindactioncreators without using its real advantages you can write it as:

const mapdispatchtoprops = dispatch => (
    bindactioncreators( { selectbook: selectbook }, dispatch )
);

or with some es6 shorthand for object keys which has the same name:

const mapdispatchtoprops = dispatch => (
    bindactioncreators( { selectbook }, dispatch )
);

this is slightly shorter than the first one. you don't need to point a function and dispatch it. you gave the action creator to bindactioncreators and it does the job for you.

now, the shorter one since you are just dispatching:

const mapdispatchtoprops = {
  selectbook,
};

even without mapdispatchtoprops:

connect( mapstatetoprops, { selectbook } )( booklist )

so, provider, connect are being provided by react-redux to make the life easier for us. mapstatetoprops and mapdispatchtoprops are the functions which connect waits. names are not important, we can use any name for them but these are the defacto ones everyone uses. the order is important and if we want to skip mapstatetoprops we must use null in its place like:

connect( null, mapdispatchtoprops )( component )

without connect actually we can use store and what it contains getstate, dispatch, subscribe in any component with two ways:

  • don't use react-redux and pass the store as prop all the way down to each component you want to use. then reach it via this.props.store.
  • use react-redux's provider, then use context for the component to get the store.

as you can imagine passing the store all the way down to components is a nightmare.

to use store with context first you need to specify the contexttypes of the component:

booklist.contexttypes = {
  store: react.proptypes.object.isrequired
};

after doing that you can grab store from this.context.store and use getstate to get the state or dispatch to dispatch your action creators.

here how our component would be if we didn't use connect:

import react, { component } from "react";
import { selectbook } from "../actions/index";

class booklist extends component {
  renderlist() {
    return this.context.store.getstate().books.map( book =>
      ( <li
        key={book.title}
        onclick={() => this.context.store.dispatch( selectbook( book ))}
      >
        {book.title}
      </li> ) );
  }

  render() {
    return (
      <ul>
        {this.renderlist()}
      </ul>
    );
  }
}

booklist.contexttypes = {
  store: react.proptypes.object.isrequired,
};

export default booklist;

here we use: this.context.store.getstate().books instead of this.props.books and this.context.store.dispatch( selectbook( book )) instead of this.props.selectbook( book ). as you can see we can reach state and can dispatch our action creators with this way. but with connect and its flexibility we open our state and action creators in a nice and clean way.


Related Query

More Query from same tag