Search code examples
reactjspatternfly

ReactJS Patternfly reduce duplicated code for dropdowns


Hi I'm having 2 Dropdowns but for that I'm managing 2 states with it. Please help me to reduce the duplicated code. Suppose, if i want to have 10 dropdowns then my number of states and same methods gets repeated the same. If there a way to refractor the code to reduce the number of states and methods would be better.

Note : I have a class based component

this.state = {
            isOpen: false,
            selected: null,
            isDisabled: false,
            isOpen1: false,
            selected1: null,
            isDisabled1: false,
           
            isOpen2: false,
            selected2: null,
            isDisabled2: false, }

Inside Constructor



  this.options = [
            <SelectOption key={0} value={hourTxt} isPlaceholder />,
            <SelectOption key={1} value={weekTxt} />,
            <SelectOption key={2} value={dayTxt} />,
            <SelectOption key={3} value={neverTxt} />, 
          ];

          this.options1 = [
            <SelectOption key={0} value={hourTxt} />,
            <SelectOption key={1} value={weekTxt} />,
            <SelectOption key={2} value={dayTxt} isPlaceholder />,
            <SelectOption key={3} value={neverTxt} />, 
          ];

     
      this.onToggle = (isOpen) => {
        this.setState({
          isOpen
        });
      };

      this.onToggle1 = isOpen1 => {
        this.setState({
          isOpen1
        });
      };

this.onSelect = (event, selection, isPlaceholder) => {
        if (isPlaceholder){

         this.clearSelection();
        }
        else {
          this.setState({
            selected: selection,
            isOpen: false
          },() => { this.postSelectData()

          });
        }
      };

      this.onSelect1 = (event, selection, isPlaceholder) => {
        if (isPlaceholder) this.clearSelection1();
        else {
          this.setState({
            selected1: selection,
            isOpen1: false
          },() => { this.postSelectData()

          });
        }
      };

 this.clearSelection = () => {
        this.setState({
          selected: null,
          isOpen: false
          },() => { this.postSelectData()
          });
       
      };

      this.clearSelection1 = () => {
        this.setState({
          selected1: null,
          isOpen1: false
        },() => { this.postSelectData()
        });
     
    };

Under render()

const {isOpen, selected,isOpen1, selected1} = this.state

Under return()


 <Select
        
          variant={SelectVariant.single}
          onToggle={this.onToggle}
          onSelect={this.onSelect}
          selections={selected}
          isOpen={isOpen}
         
          
        >
         {this.options}
         
        </Select>
 <Select
              variant={SelectVariant.single}
              onToggle={this.onToggle1}
              onSelect={this.onSelect1}
              selections={selected1}
              isOpen={isOpen1}
              
            >
              {this.options1}
            </Select>


Solution

  • To avoid code duplication you can abstract the logic that would be duplicated into a component and then create multiple instances of that component. How much can or cannot be reused depends on the specific requirements at hand.

    In your case, you could create a Dropdown component that has all the static parts, generic logic, and the related handler functions. Everything that is specific for each instance, in turn, must be managed by the parent component and passed on to the dropdown component (typically as props).

    The snippet below might help you achieve what you want. It's a basic dropdown component that offers a enabling/disabling toggle (general logic) and contains all the static parts (e.g., <select>, default value). The parent component (App) renders multiple instances of the Dropdown component by passing it the specifics (label, options, onChange action) as props. Through the onChange action, the state in the parent component will be updated with the value selected last in either of the dropdowns.

    const { useState } = React;
    
    const Dropdown = (props) => {
      const [disabled, setDisabled] = useState(false);
      return (
        <div>
          {props.label}
          <button onClick={() => setDisabled(!disabled)}>{disabled ? "enable" : "disable"}</button>
          <br />
          <select onChange={(e) => props.action(e.target.value)} disabled={disabled}>
            <option value="default">I am a default value</option>
            {props.options.map((o) => (
              <option value={o.value}>{o.label}</option>
            ))}
          </select>
        </div>
      );
    };
    const App = () => {
      const dropdown1 = {
        label: "My first Dropdown",
        options: [
          { value: "value1", label: "entry1" },
          { value: "value2", label: "entry2" },
          { value: "value3", label: "entry3" },
        ],
        action: (val) => setLastSelectedValue(val),
      };
    
      const dropdown2 = {
        label: "My second Dropdown",
        options: [
          { value: "value4", label: "entry4" },
          { value: "value5", label: "entry5" },
          { value: "value6", label: "entry6" },
        ],
        action: (val) => setLastSelectedValue(val),
      };
    
      const [lastSelectedValue, setLastSelectedValue] = useState();
    
      return (
        <div>
          <Dropdown {...dropdown1} />
          <Dropdown {...dropdown2} />
          {lastSelectedValue && <p>Last selected value: {lastSelectedValue}</p>}
        </div>
      );
    };
    
    ReactDOM.render(<App />, document.getElementById("root"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
    <div id="root"></div>