Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useDrop DropTargetHookSpec accept type should include a function type #2732

Open
TheBolliwood opened this issue Aug 20, 2020 · 6 comments
Open

Comments

@TheBolliwood
Copy link

Describe the bug
Your documentation of useDrop says that the specification object member accept is "A string, an ES6 symbol, an array of either, or a function that returns either of those, given component's props.".
But in the code, accept is defined as TargetType, which is string | symbol or an array of those.

Expected behavior
accept should be a type where a function which returns TargetType is possible.

Additional context
I want to update accept dynamically. I thought this would be possible by changing the accept value of useDrop but this doesn't work. I currently don't see how to do this otherwise and I can't find the behavior the documentation describes.

@johanneslumpe
Copy link

I know this isn't an ideal solution, but until this is solved and we can have target type-production functions, a workaround would be to use a key property equal to your accepted types on the component which contains your drop target. This would ensure that it re-mounts once you change the acceptable type(s). I just ran into this exact issue myself today.

@dhulme
Copy link

dhulme commented Oct 6, 2020

I noticed this too, but got around it by using canDrop.

@ranneyd
Copy link
Contributor

ranneyd commented Nov 18, 2020

I know this isn't an ideal solution, but until this is solved and we can have target type-production functions, a workaround would be to use a key property equal to your accepted types on the component which contains your drop target. This would ensure that it re-mounts once you change the acceptable type(s). I just ran into this exact issue myself today.

Just to echo this comment: I had a situation where I had a ternary that was rendering two versions of the same component based on a boolean. Clever react realized they are the same component but with different props. Although I tried to use this ternary to render them as independent nodes that mount/unmount based on the boolean, it was actually rerendering instead of remounting. Thus, the accept was based on the original props, not the new ones, and useDrop doesn't update based on that prop changing.

yehuozhili added a commit to yehuozhili/react-dnd that referenced this issue Dec 26, 2020
@DannyChambers
Copy link

I know this isn't an ideal solution, but until this is solved and we can have target type-production functions, a workaround would be to use a key property equal to your accepted types on the component which contains your drop target. This would ensure that it re-mounts once you change the acceptable type(s). I just ran into this exact issue myself today.

Really sorry, but I don't understand what to do, would it be possible to see an example/code snippet?

@ranneyd
Copy link
Contributor

ranneyd commented Feb 3, 2021

I know this isn't an ideal solution, but until this is solved and we can have target type-production functions, a workaround would be to use a key property equal to your accepted types on the component which contains your drop target. This would ensure that it re-mounts once you change the acceptable type(s). I just ran into this exact issue myself today.

Really sorry, but I don't understand what to do, would it be possible to see an example/code snippet?

The problem/solution are really simple. Basically the code/docs agree that it should take a function, but TypeScript types don't, so they need to be updated to reflect the actual behavior.

I should have fixed it instead of commenting in Nov but I was lazy. I'll have a PR up in 1 hour so don't sweat it.

So it turns out DropTarget is both typed correctly and functionally correct. However, useDrop, which is the hooks implementation of the same thing, actually does not support a function for accept (it isn't just an incorrect typing, as we thought; it doesn't support it at all). It seems like the docs were either errantly copy/pasted or the implementation was meant to support a function for accept but didn't.

Updating to include the functionality is tricky for a few reasons:

  1. The type is used in a variety of places and the accept value is passed through many different functions/registries/handlers/etc. There is also at least one place where it validates the type using invariant
  2. The docs say that accept takes the "props of the component". That makes sense for an HOC (which DropTarget is) but doesn't really make sense for the hook. As I think about it I realize I don't know what the logical equivalent would be.
  3. Because of the above, obviously, the type of "props" isn't available in the type definition for useDrop, so you can't write a type for a function that takes args of type "props".

The way DropTarget does it is pretty simple: in the beginning it does (paraphrasing) let getType = accept;, then if (typeof accept !== "function") getType = () => accept. Then for the rest of the function it treats it as a function. In order to do that here we'd need to figure out when we have access to "props" (whatever that may be), then do this, then everywhere thereafter change the code to call it like a function.

The solution may be to either just update the docs to remove the mention of a function, or make it take a function that gets no arguments. In the latter, at least you can do useCallback or something so useDrop can fetch an up-to-date type. That's probably the most hooks-y way to do it?

@OrenMag
Copy link

OrenMag commented Oct 4, 2021

Any update on it? We have the same problem, and using canDrop seems like a not-my-most-favrorite workaround

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment