Skip to content

Instantly share code, notes, and snippets.

@bnorton
Last active July 6, 2024 09:56
Show Gist options
  • Save bnorton/e40560df501a6803692cdb787ee3d5a0 to your computer and use it in GitHub Desktop.
Save bnorton/e40560df501a6803692cdb787ee3d5a0 to your computer and use it in GitHub Desktop.
Chameleon React Developer technical exercise
/*
Prompt:
We have defined a basic dropdown via the Dropdown and DropdownItem components below, with example usage
in the ExampleNav component. The Dropdown and DropdownItem components have some problems, and also
have room for improvements (doesn't everything?) A couple items TODO here (make sure to explain with comments!)
0. How are you today? 😊
1. Please fix any obvious issues you see with the dropdown.
2. Please then make improvements to the dropdown.
3. Consider the different ways that this dropdown might be used and what changes would
be neccessary to make it more flexible.
4. If we wanted to sync this dropdown selection to the server with
app.sync('PATCH', 'user', { dropdown_1_state: {true,false} }) where would this be included?
5. If we wanted to pass children (like this example) OR a Promise that resolves to an array of items
what changes should be made? (just a sentence or two or some code is ok).
PS: No need to worry about CSS.
*/
import React, {PureComponent} from 'react';
class Dropdown extends PureComponent {
constuctor(props) {
super(props);
this.state = {
isOpen: false,
};
}
toggle() {
const {isOpen} = this.state;
this.setState({isOpen: isOpen});
}
render() {
const {isOpen} = this.state;
const {label} = this.props;
return (
<div className="dropdown">
<button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expended={isOpen} onClick={this.toggle}>{label}</button>
<ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
{this.props.children}
</ul>
</div>
);
}
}
class DropdownItem extends PureComponent {
render() {
// TODO implement me
}
}
class ExampleNav extends PureComponent {
render() {
return (
<nav>
<a href="/page1">Page 1</a>
<Dropdown label="More items">
<DropdownItem href="/page2">Page 2</DropdownItem>
<DropdownItem href="/page3">Page 3</DropdownItem>
<DropdownItem href="/page4">Page 4</DropdownItem>
</Dropdown>
<Dropdown label="Even more items">
<DropdownItem href="/page5">Page 5</DropdownItem>
<DropdownItem href="/page6">Page 6</DropdownItem>
</Dropdown>
</nav>
);
}
}
@srsedev
Copy link

srsedev commented Jun 29, 2021

import React, {PureComponent} from 'react';

class Dropdown extends PureComponent {
//////constuctor->constructor
  constructor(props) {
    super(props);
    this.state = {
      isOpen: false,
    };
  }

  toggle() {
    const {isOpen} = this.state;

    this.setState({isOpen: isOpen});
  }

  render() {
    const {isOpen} = this.state;
    const {label} = this.props;

    return (
      <div className="dropdown">
        <button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expended={isOpen} onClick={this.toggle}>{label}</button>

        <ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
          {this.props.children}
        </ul>
      </div>
    );
  }
}

class DropdownItem extends PureComponent {
  render() {
/////return
    return(
    <>
    </>
    )
  }
}

class ExampleNav extends PureComponent {
  render() {
    return (
      <nav>
        <a href="/page1">Page 1</a>
        <Dropdown label="More items">
          <DropdownItem href="/page2">Page 2</DropdownItem>
          <DropdownItem href="/page3">Page 3</DropdownItem>
          <DropdownItem href="/page4">Page 4</DropdownItem>
        </Dropdown>
        <Dropdown label="Even more items">
          <DropdownItem href="/page5">Page 5</DropdownItem>
          <DropdownItem href="/page6">Page 6</DropdownItem>
        </Dropdown>
      </nav>
    );
  }
}

@Maryjanee
Copy link

Maryjanee commented Jul 1, 2021

import React, { PureComponent } from "react";

class Dropdown extends PureComponent {
  // Updated the name from `constuctor` to `constructor`
  constructor(props) {
    super(props);
    this.state = {
      isOpen: false
    };
  }

  // Converted this to an arrow function so the `this` is bound to class
  toggle = () => {
    const { isOpen } = this.state;

    // Updated the assignment to use the negated form, for toggle to work
    this.setState({ isOpen: !isOpen });
  };

  render() {
    const { isOpen } = this.state;
    const { label } = this.props;

    return (
      <div className="dropdown">
        {/* change aria-expended to aria-expanded */}
        <button
          type="button"
          className="dropdown-button"
          id="dropdownButton"
          aria-haspopup="true"
          aria-expanded={isOpen}
          onClick={this.toggle}
        >
          {label}
        </button>

        <ul
          className={`${isOpen ? "dropdown-open" : ""} dropdown-menu`}
          aria-labelledby="dropdownButton"
          role="menu"
        >
          {this.props.children}
        </ul>
      </div>
    );
  }
}

class DropdownItem extends PureComponent {
  render() {
    // Returned an anchor element, rendering the props passed
    return <a href={this.props.href}>{this.props.children}</a>;
  }
}
// Exported the ExampleNav Component
export default class ExampleNav extends PureComponent {
  render() {
    return (
      <nav>
        <a href="/page1">Page 1</a>
        <Dropdown label="More items">
          <DropdownItem href="/page2">Page 2</DropdownItem>
          <DropdownItem href="/page3">Page 3</DropdownItem>
          <DropdownItem href="/page4">Page 4</DropdownItem>
        </Dropdown>
        <Dropdown label="Even more items">
          <DropdownItem href="/page5">Page 5</DropdownItem>
          <DropdownItem href="/page6">Page 6</DropdownItem>
        </Dropdown>
      </nav>
    );
  }
}

// I am not sure the middleware app.sync() exists .

@abhishekp3099
Copy link

abhishekp3099 commented Jul 2, 2021 via email

@bilalkhalidshaikh
Copy link

import React, {PureComponent} from 'react';

class Dropdown extends PureComponent {
//////its "constructor" not constuctor.
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
}

toggle() {
const {isOpen} = this.state;

this.setState({isOpen: isOpen});

}

render() {
const {isOpen} = this.state;
const {label} = this.props;

return (
  <div className="dropdown">
    <button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expended={isOpen} onClick={this.toggle}>{label}</button>

    <ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
      {this.props.children}
    </ul>
  </div>
);

}
}

class DropdownItem extends PureComponent {
render() {
/////return
return(
<>
</>
)
}
}

class ExampleNav extends PureComponent {
render() {
return (


Page 1

Page 2
Page 3
Page 4


Page 5
Page 6


);
}
}

@olahbold
Copy link

olahbold commented Jul 5, 2021

import React, {PureComponent} from 'react';

class Dropdown extends PureComponent {
constructor ==> not spelt right
constuctor(props) {
super(props);
this.state = {
isOpen: false,

this.toggle = this.toggle.bind(this)
};
}

toggle() {
const {isOpen} = this.state;
//Not is included
this.setState({isOpen: !isOpen});
}

render() {
const {isOpen} = this.state;
const {label} = this.props;

return (
  <div className="dropdown">
    <button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expended={isOpen} onClick={this.toggle}>{label}</button>

    <ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
      {this.props.children}
    </ul>
  </div>
);

}
}

class DropdownItem extends PureComponent {
render() {
Add a return statement
return {this.props.children}
}
}

class ExampleNav extends PureComponent {
render() {
//I think the app.sync should be included here
return (


Page 1

Page 2
Page 3
Page 4


Page 5
Page 6


);
}
}

@hiagogranelli
Copy link

import React, {PureComponent} from 'react';

class Dropdown extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      isOpen: false,
      
    };
  }

  toggle = () => {
    const {isOpen} = this.state;

    this.setState({isOpen: !isOpen});
  }

  render() {
    const {isOpen} = this.state;
    const {label} = this.props;

    return (
      <div className="dropdown">
        <button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expanded={isOpen} onClick={this.toggle}>{label}</button>

        <ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
          {this.props.children}
        </ul>
      </div>
    );
  }
}

class DropdownItem extends PureComponent {
  render() {
    // TODO implement me
    return (
      <a href={this.props.href}>
        {this.props.children}
      </a>
    )
  }
}

class App extends PureComponent {
  render() {
    return (
      <nav>
        <a href="/page1">Page 1</a>
        <Dropdown label="More items">
          <DropdownItem href="/page2">Page 2</DropdownItem>
          <DropdownItem href="/page3">Page 3</DropdownItem>
          <DropdownItem href="/page4">Page 4</DropdownItem>
        </Dropdown>
        <Dropdown label="Even more items">
          <DropdownItem href="/page5">Page 5</DropdownItem>
          <DropdownItem href="/page6">Page 6</DropdownItem>
        </Dropdown>
      </nav>
    );
  }
}

export default App
```html

@WCanirinka
Copy link

`import React, {PureComponent} from 'react';

class Dropdown extends PureComponent {
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
}

toggle = () => {
const {isOpen} = this.state;

this.setState({isOpen: !isOpen});

}

render() {
const {isOpen} = this.state;
const {label} = this.props;

return (
  <div className="dropdown">
    <button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expanded={isOpen} onClick={this.toggle}>{label}</button>

    <ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
      {this.props.children}
    </ul>
  </div>
);

}
}

class DropdownItem extends PureComponent {
render() {
// TODO implement me
return {this.props.children}
}
}

export default class ExampleNav extends PureComponent {
render() {
return (


Page 1

Page 2
Page 3
Page 4


Page 5
Page 6


);
}
}`

@friilancer
Copy link

friilancer commented Jul 9, 2021

{
  /*
    3. Considering other cases would boil down to forms or any kind of interactive UI that changes based on user selection. If it is strictly for navigation then this implementation would work most of the time. In other cases, we would be looking to implement an array and map() to automatically generate our components.
    4. If we want to sync it with the server, then we would be looking at an async function in our componentDidUpdate lifecycle method or the
    useEffect hook in the case of functional components
    5. We would have an empty array as one of our states, the array's state would be updated at the end of the async call.
    The array would then be mapped and displayed on the UI
  */
}

import React, {PureComponent} from 'react';

class Dropdown extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      isOpen: false,
    };
  }
  {/*Updated toggle to an arrow function, this now points to class component*/}
  toggle = () => {
    {/*Updated setState to a function with the isOpen as an argument, which is better practice incase of batch setState calls in application*/}
    this.setState(({isOpen}) => ({isOpen: !isOpen}));
  }

  render() {
    const {isOpen} = this.state;
    const {label} = this.props;
{/*Updated aria-expended to aria-expanded*/}
    return (
      <div className="dropdown">
        {/*Updated aria-expended to aria-expanded*/}
        <button type="button" className="dropdown-button" id="dropdownButton" aria-expanded={isOpen} aria-haspopup="true" onClick={this.toggle}>{label}</button>
        {/*Dropdown now works on toggle*/}
        <ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
          {isOpen && this.props.children }
        </ul>
      </div>
    );
  }
}
class DropdownItem extends PureComponent {
  render() {
    // TODO implement me
    return(
      {/*Dropdown Item now receives children and renders accordingly*/}
      <a href={this.props.href}>{this.props.children}</a>
    );
  }
}

class ExampleNav extends PureComponent {
  render() {
    return (
      <nav>
        <a href="/page1">Page 1</a>
        <Dropdown label="More items">
          <DropdownItem href="/page2">Page 2</DropdownItem>
          <DropdownItem href="/page3">Page 3</DropdownItem>
          <DropdownItem href="/page4">Page 4</DropdownItem>
        </Dropdown>
        <Dropdown label="Even more items">
          <DropdownItem href="/page5">Page 5</DropdownItem>
          <DropdownItem href="/page6">Page 6</DropdownItem>
        </Dropdown>
      </nav>
    );
  }
}

@JoshuaRotimi
Copy link

import React, { PureComponent } from "react";

class Dropdown extends PureComponent {
// Changed the name from constuctor to constructor
constructor(props) {
super(props);
this.state = {
isOpen: false
};
}

// Converted the toggle function to an arrow function so the this is bound to the class
toggle = () => {
const { isOpen } = this.state;

// Updated the setStateCall to use the opposite of the current state value for the toggle to work
this.setState({ isOpen: !isOpen });

};

render() {
const { isOpen } = this.state;
const { label } = this.props;

return (
  <div className="dropdown">
    {/* changed aria-expended to aria-expanded */}
    <button
      type="button"
      className="dropdown-button"
      id="dropdownButton"
      aria-haspopup="true"
      aria-expanded={isOpen}
      onClick={this.toggle}
    >
      {label}
    </button>

    <ul
      className={`${isOpen ? "dropdown-open" : ""} dropdown-menu`}
      aria-labelledby="dropdownButton"
      role="menu"
    >
      {this.props.children}
    </ul>
  </div>
);

}
}

class DropdownItem extends PureComponent {
render() {
// Returned an anchor element, rendering the props passed
return {this.props.children};
}
}
// Exported the ExampleNav Component
export default class ExampleNav extends PureComponent {
render() {
return (


Page 1

Page 2
Page 3
Page 4


Page 5
Page 6


);
}
}

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