1

I'm using ReactJS, and shopify's polaris in order to create a website. I'm very new to react so this might be a newbie question but I looked over the internet and couldn't manage to put the pieces together.

I have a dropdown list and basically whenever the user clicks on an item from a list I want to add a button next to the dropdown. Here is my code:

import React from "react";
import { ActionList, Button, List, Popover } from "@shopify/polaris";

export default class ActionListExample extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      active: false,
      title: "Set Period",
    };
  }

renderButton() {
    console.log("Button clicked")
    return (
      <div>
        <Button fullWidth={true}>Add product</Button>;
      </div>
    );
 }

togglePopover = () => {
this.setState(({ active }) => {
  return { active: !active };
});
};

render() {
  const activator = (
    <Button onClick={this.togglePopover}>{this.state.title}</Button>
  );
return (
  <div style={{ height: "250px" }}>
    <Popover
      active={this.state.active}
      activator={activator}
      onClose={this.togglePopover}
    >
      <ActionList
        items={[
          {
            content: "One",
            onAction: () => {
              this.setState({ title: "One" }, function() {
                this.togglePopover();
                this.renderButton() //THIS IS WHERE I CALL THE METHOD
              });
            }
          }
        ]}
      />
    </Popover>
  </div>
);
}
}

I've placed a comment in the code to show where I call the renderButton() method. Whenever I click the "One" element in the dropdown, it prints out "Button clicked" but nothing gets rendered to the screen. Any help is greatly appreciated. Thanks in advance!

tee
  • 1,286
  • 2
  • 19
  • 35

3 Answers3

2

You need to add another variable to check if an item is clicked, and as @azium commented, you need to add the output to your JSX, not inside the onAction function.

As of right now, you close the Popper when an item is clicked, setting this.state.active to false, so you can't rely on that to render your button. You need to add something like this.state.isButton or something and in onAction include:

onAction: () => {
  this.setState({ title: "One", isButton: true }, () => {
    this.togglePopover();
   });
}

and then in your JSX:

{this.state.isButton && this.renderButton()}
izb
  • 562
  • 4
  • 11
0

This is a perfect use case for conditional rendering.
You basically want to render a component based on a condition (Boolean from your state in this case).

Conditional rendering can be written is several ways as you can see in the docs.

In your case i would go for something like this:

return (
  <div style={{ height: "250px" }}>
    <Popover
      active={this.state.active}
      activator={activator}
      onClose={this.togglePopover}
    >
      <ActionList
        items={[
          {
            content: "One",
            onAction: () => {
              this.setState({ title: "One" }, function() {
                this.togglePopover();
              });
            }
          }
        ]}
      />
      {this.state.active && this.renderButton()}
    </Popover>
  </div>
);
}
}

Note that i just placed it at a random place, feel free to move it wherever you need it in the markup.

Sagiv b.g
  • 30,379
  • 9
  • 68
  • 99
  • Hello @Sagiv b.g. Doing what you suggested created a button in the dropdown list. I wanted a button to appear next to the dropdown whenever I clicked on the item in the dropdown list. – tee Sep 17 '18 at 22:28
  • So when `this.state.active` is not an indicator you clicked the item? – Sagiv b.g Sep 17 '18 at 22:36
  • I don't understand what you mean by that but I posted a solution here that finally worked. I combined everyones idea. It was basically what you did except I added a isButton in the state. – tee Sep 17 '18 at 23:01
  • this is exactly what i meant, in your case `isButton` is the indicator (the condition) to whether or not render the component. the important part is **How** you render conditionally (which i showed you in my answer and provided the links to the docs), the condition itself is depended on your logic. – Sagiv b.g Sep 17 '18 at 23:21
-1

Thanks to everyone's help I finally was able to do this. I placed an extra attribute in the state called isButton and I initially set it equal to false. Here is my render function:

render() {
 const activator = (
   <Button onClick={this.togglePopover}>{this.state.title}</Button>
 );
return (
  <div style={{ height: "250px" }}>
    <Popover
      active={this.state.active}
      activator={activator}
      onClose={this.togglePopover}
    >
      <ActionList
        items={[
        {
        content: "One",
        onAction: () => {
          this.setState({ title: "One", isButton: true }, function() { //Set isButton to true
            this.togglePopover();
          });
        }
      }
    ]}
  />
{this.state.isButton && this.renderButton()} //ADDED HERE
</Popover>
  </div>
);
}

Please look at the comments to see where code was changed. Thanks!

tee
  • 1,286
  • 2
  • 19
  • 35