React-beautiful-dnd: Dynamically change hooks after first render

Created on 21 Aug 2017  路  5Comments  路  Source: atlassian/react-beautiful-dnd

I was playing with this library on a toy side-project, and I noticed I cannot dynamically change hooks, especially after the first render.

The gist of the code I had is as follows:

import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";

import { compose, withState } from "recompose";

// fake data generator
const getItems = count =>
    Array.from({ length: count }, (v, k) => k).map(k => ({
        id: `item-${k}`,
        content: `item ${k}`,
        type: generateType(k)
    }));

// ...

const onDragEnd = setCards => result => {
    // dropped outside the list
    if (!result.destination) {
        return;
    }

    setCards(prevCards => {
        const nextCards = reorder(
            prevCards,
            result.source.index,
            result.destination.index
        );
        return nextCards;
    });
};

const Board = props => {
    const { cards, setCards } = props;

    return (
        // NOTE: unable to replace onDragEnd after first render
        <DragDropContext onDragEnd={onDragEnd(setCards)}>
            <Droppable droppableId="droppable">
                {generateBoard(cards)}
            </Droppable>
        </DragDropContext>
    );
};

const cardsState = withState("cards", "setCards", getItems(10));

export default compose(cardsState)(Board);

Even though the drag and drop (which is awesome by the way) appears to work fine, after the first render, the generated function from onDragEnd(setCards) is not replaced within DragDropContext.

This is likely to do with the fact there is no componentWillReceiveProps() (or similar) at https://github.com/atlassian/react-beautiful-dnd/blob/0f557e036fc5bdedeb5ba13de9540de28883aa4a/src/view/drag-drop-context/drag-drop-context.jsx#L17-L46


Even though the above example uses recompose, one may refactor the above to use redux and friends (e.g. react-redux), whereby the developer can pass dispatch (or a binded dispatch) to onDragEnd(). You cannot really assume dispatch won't change after the first render.

new feature 馃帹

All 5 comments

This behaviour is currently not supported:

Dynamic hooks

Your hook functions will only be captured once at start up. Please do not change the function after that. If there is a valid use case for this then dynamic hooks could be supported. However, at this time it is not.

-> README.md

The functions are passed onto a redux middleware at startup and not looked at again. This could be improved for sure. This looks like a valid use case.

This should be fairly easy to do - we just need to move away from using a redux middleware and set up a subscription to the store within the DragDropContext component.

I am fiddling with this while away :)

This has now shipped @dashed. Enjoy!

@alexreardon thanks for taking the time to look into this! 馃槃 I'll definitely check it out.

Was this page helpful?
0 / 5 - 0 ratings