ResourcePicker selection(s)

Solved
Highlighted
Shopify Expert
4182 29 402

I have a component system that renders some children. One of the children is a Resource Picker. I am also rendering a ResourceList where the items have a bulk selection action.

 

The bulk selection action needs to know the result of the resource picker. When I select a resource, a single product, the selection triggers a render on a component and all is well. But the parent does not know about the product selected, nor does the bulk action function.

 

How does a child/sibling component end up passing that value back up to the parent for use in a function like bulk actions? All my efforts to date have resulted in some message about causing a memory leak blah blah...

 

What is the surest way to do this? I am about to just set a fricking cookie and be done with the whole use React properly thing. It seems super hard to just pass an ID around. What is the trick to having some high-level value (say my product ID is 0 to begin with) get passed down to a child for mutation to an actual ID, so I can use it later?

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
0 Likes
Highlighted
Shopify Expert
4182 29 402

As a sample...

Parent product <Parent> has two kids <Details> and <SomeList>

 

<SomeList> eventually runs a bulk action on selected records, but must know the value of something done in <Details>. <Details> it turns out has a <ResourcePicker> which works a peach, with a sibling that <DisplaysTheProductSelected>. So getting the value from <ResourcePicker> to <DisplaysTheProductSelected> is where I have the problem. I moved a useState() hook into <Details>. I pass the setter function to <ResourcePicker> and so when the time comes to set the product, <Details> knows. The <DisplayTheProductSelected> has a prop for the resulting selected product.

 

All that works, except the console, blows chunks on a memory-leak you're doing it all wrong error.

 

That is where I go bonkers... and hate ... the fluff of declarative React is not so nice. So simple. Select a product, and use that all over. Except what? I envision the solution being brain-dead simple.

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
0 Likes
Highlighted
Shopify Staff
Shopify Staff
1040 140 165

 I moved a useState() hook into <Details>. I pass the setter function to <ResourcePicker> and so when the time comes to set the product, <Details> knows. The <DisplayTheProductSelected> has a prop for the resulting selected product.

Sounds reasonable at first glance. Does the code look something like this? https://codesandbox.io/s/stoic-kilby-6g7wd?file=/index.js

 

 

0 Likes
Highlighted
Shopify Expert
4182 29 402

I had the exact same thing in mind, with the addition of the resource picker. I watch things carefully in the console. Components initially load and state is set, and props are passed. OK. So now I check, and if my resource list selections are available, BUT I have selected product from the ResourcePicker, I cannot continue.

So now I select a product. I have to propagate that selection up to the parent, and also over to the sibling resource list handler. So when I do my selection, all works, but I get a pesky message about memory leaks, and not having used a useEffect hook or something. But, my value was propagated! If I do anything else, no other warnings ever fire. It is only the first time I do a selection.

So I followed all the React guides of passing props down, and event handlers as props, but for a reason I cannot yet figure, the use of a prop passed state change function inside the handler of the resource picker, is out of whack with the component mounting. So for now, I guess it is safe to ignore. Everything works but there is a console warning.

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
0 Likes
Highlighted
Shopify Expert
4182 29 402

After editing your code to make it closer to my needs, I see something I may be able to borrow. Where you are lifting the selection from SomeList up to Details, and where I have a ResourcePicker child in Details, it seems I should be able to move my logic from testing the selection of the ResourcePicker from the SomeList, to the Details. Maybe that simplifies things and makes the bad guy go away.

 

We'll see this weekend. Thank. Not sure how to test Polaris App Bridge components out like this... I guess by pasting in all the needed props it should just work?

 

 

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
1 Like
Highlighted
Shopify Expert
4182 29 402

I narrowed the problem down to the ResourcePicker object itself. I render it with a single prop, pointing to a useState setter.

 

    <ProductPicker onSelect={onSelectProduct} />

 

When the picker handleSelect function receives the selection, I call onSelect(selection) and that indeed is propagated to the parent useCallback function that triggers of a change to the product state. The problem remains with an error from this sequence of events. I can think of no good reason for this error, but a React expert might know.

 

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    in ProductPicker (at details.js:124)

The component is pretty simple. A React App Bridge Polaris Product Picker... accepting a single prop, which is the useState from a parent. Can anyone point out why this fails? Something in the setup of the handleResourcePickerClose and handleSelection is not right?

 

function ProductPicker({ onSelect }) {
    const [active, setActive] = useState(false);
    const handleResourcePickerClose = useCallback(() => setActive(false), []);
    const handleSelection = useCallback(
      ({ selection }) => {
        onSelect(selection[0]);
        handleResourcePickerClose();
      },
      [handleResourcePickerClose],
    );
    const togglePicker = useCallback(() => setActive(true), []);
    return (
      <>
        <Button primary onClick={togglePicker}>Shopify Product Picker</Button>
        <ResourcePicker
          actionVerb={ResourcePicker.ActionVerb.Select}
          resourceType="Product"
          showVariants={false}
          allowMultiple={false}
          open={active}
          onSelection={handleSelection}
          onCancel={handleResourcePickerClose}
        />
      </>
    );
  }
Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
0 Likes
Highlighted
Shopify Expert
4182 29 402

This is an accepted solution.

I solved this by getting rid of the event handler in the picker, so that the set selection is transferred to the parent callback. And like that. Wow. Bug gone. So much nice.

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
1 Like