Search code examples
javascriptreactjsantd

Antd <Option> changes render behavior by the pure existence of non executed(!) code


I am using Ant Design for the first time in a project. Using the <Option> and <Select> component I have run into the strangest bug I've ever had. The pure existence if code, which is NOT EXECUTED changes the render behavior of the <Option>.

The difference is, that the first time (with the code) it displays a number (3) in the <Option> and the second time (without the code) it displays a string ("Schraube").

I don't know how much code I am allowed to share, but I recorded a short video which shows the bug.

(The code which prints "GETS CALLED" only runs after I change the select option, during the render process it doesn't get executed.)

https://www.youtube.com/watch?v=aY2NPgP5x6A

I'd like to hear your thoughts on it.


Solution

  • In the first case, you have:

    if (a) {
        console.log("GETS CALLED");
        return false;
    }
    
    return true;
    

    When this code gets executed, your option isn't formatted to a user-friendly display.

    In the second you have just:

    return true;
    

    In which case it is being formatted correctly.

    Note this is not just removing the console.log statement, and you're not just enabling some trivial if statement. You're changing the the return value of the function. Since this is in a call to .filter you're changing what values get passed to .map which actually formats the option for display purposes.

    If you were to try:

    if (a) {
        console.log("GETS CALLED");
    }
    
    return true;
    

    You'd see that the value gets formatted, and your console.log statement gets hit.

    Update What I think you're trying to accomplish is to have the second dropdown exclude the option that was selected in the first dropdown. In that case you'll need to render different option arrays for each item. Also be sure to include the item that is selected for the current dropdown, so that the display is correct on the selected item. Something along these lines should help:

    const orderForm = this.state.order.map((o, i) => {
       const options = this.state.parts
           .filter(p => {
               // look for any *other* order that has this part id selected
               const a = this.state.order.find((o2) => o2 !== o && o2.partId === p.id);
               return !a;
           })
           .map((p) => (<Option ... />));
    
       return (
          <Select>
             {options}
          </Select>
       );
    });
    

    Or if you want to render the <Option>'s only once, you could do something like this:

    const allOptions = this.state.parts.map((p) => [p.id, (<Option ... />)]);
    
    const orderForm = this.state.order.map((o, i) => {
       const options = allOptions 
           .filter(([partId]) => {
               // look for any *other* order that has this part id selected
               const a = this.state.order.find((o2) => o2 !== o && o2.partId === partId);
               return !a;
           })
           .map(([_, opt]) => opt);
    
       return (
          <Select>
             {options}
          </Select>
       );
    });