Ad

React Redux - Trouble Trying To Use React-DnD And MapDispatchToProps

- 1 answer

I was wondering why couldn't I get some of my components to work using ReactDnD and mapDispatchToProps.

I'm trying to drag and drop Services to Clients but I can't find my dispatch functions in props at my serviceSpec on the endDrag method.

Considering my mapDispatchToProps on my Service component:

const mapDispatchToProps = (dispatch) => ({
  dragService: (service) => { dispatch(dragService(service)) },
  dropService: (service, clientTarget) => { dispatch(dropService(service, clientTarget)) }
});

High-order functions to bond together DragSource + Service + State + Dispatch:

var reduxConnectedService = connect(mapStateToProps, mapDispatchToProps)(Service);
export default DragSource('service', serviceSpec, collect)(reduxConnectedService);

render() method:

render (){
    const { isDragging, connectDragSource, service } = this.props;
    return connectDragSource(
      <a className="panel-block is-active">
        <CategoryIcon category={service.category}/>
        {service.name} | ${service.price}
      </a>
    )
  }

The spec object used to implement the dragSource specification (here is the problem):

const serviceSpec = {
  beginDrag(props) {
    return props.service;
  },
  endDrag(props, monitor, component){
    console.log(props);
  }
}

The console.log at endDrag function just show my Service Object because is being returned on the beginDrag function:

{service: {…}}

But my plan was to dispatch the action dropService here on endDrag, but I couldn't. The documentation says that (http://react-dnd.github.io/react-dnd/docs/api/drag-source):

beginDrag(props, monitor, component): Required. When the dragging starts, beginDrag is called. You must return a plain JavaScript object describing the data being dragged. What you return is the only information available to the drop targets about the drag source so it's important to pick the minimal data they need to know. You may be tempted to put a reference to the component into it, but you should try very hard to avoid doing this because it couples the drag sources and drop targets. It's a good idea to return something like { id: props.id } from this method.

I don't believe that I should return the dropService(dispatch) function on the beginDrag definition. So after hours trying to make it work, I started to pass the dropService function as a prop directly through the parent component (ServiceList):

{this.props.filteredServices.map((service, index) => (
     <Service service={service} key={service.name} dropService={this.props.dropService}/>
))}

Making this way I could dispatch the dropService action on the endDrag method like I wanted, the console.log can proves that:

{service: {…}, dropService: ƒ}

I could make it work but I can't understand why I couldn't get this to work using mapDispatchToProps. Is there any limitation while using React-DnD or am I making something wrong?

Any help will be appreciated, I cannot die with this doubt. Thank you in advance.

Ad

Answer

Your problem is with these two lines:

var reduxConnectedService = connect(mapStateToProps, mapDispatchToProps)(Service);
export default DragSource('service', serviceSpec, collect)(reduxConnectedService);

Note the order: you wrap Service into a Redux container. Then you wrap the Redux Container with the DragSource container. Thus, in the component tree, the drag container is the parent of the Redux container, which means it doesn't receive the Redux props from it.

To fix that, make the drag container the child of the Redux container. You can do so by simply swapping the DragSource() and connect() calls:

var dragService = DragSource('service', serviceSpec, collect)(Service);
var reduxConnectedService = connect(mapStateToProps, mapDispatchToProps)(dragService);
Ad
source: stackoverflow.com
Ad