4
\$\begingroup\$

Task Description:

  • Create a div-element and take control over it using a Vue-Instance.

  • Print an array of hobbies into the div-element. Provide some default hobbies.

  • Add a 'New Hobby' button and a text-input element. So that the user
    can add additional hobbies.

  • When a hobby list-item is clicked, it shall be removed from the list.

  • Add a "Hobby deleted"-paragraph which is only shown when a hobby-item has been deleted at least one time.

  • Above the list of hobbies add a hobby-counter which shows the current count of hobby-items.

  • Style the hobby-list depending on whether you have more or less then 3 hobbies in the list.

  • Outsource your hobbies (the list-item elements) into a component (so that it becomes re-usable).

The source-code of my solution:

// ----- index.js ----------
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

// --------- App.js ----------
import React, { Component } from 'react';
import { Hobbies } from './Hobbies';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Hobbies />
      </div>
    );
  }
}

export default App;

// ------------ Hobbies.js --------------
import React, { Component } from 'react';
import { HobbyItem } from './HobbyItem';

class Hobbies extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            hobbies: [
                'Reading',
                'Sport',
                'Music',
                'Chess',
                'Cooking'
            ],
            deleted: false
        }
    }

    addHobby(event) {
        let currentHobbies = this.state.hobbies;
        let textBox = event.target.previousElementSibling;

        if (textBox.value) {
            currentHobbies.push(textBox.value);
            textBox.value = '';

            this.setState({
                hobbies: currentHobbies
            });
        }
    }

    removeHobby(event) {
        let currentHobby = event.target.textContent;
        let updatedHobbies = this.state.hobbies.filter((hobby) => {
            return currentHobby !== hobby;
        });

        this.setState({
            hobbies: updatedHobbies
        });

        !this.state.deleted && this.setState({
            deleted: true
        });
    }

    render() {
        let cssHobbyItem = 'hobby-item';
        let cssCounter = 'more-three';
        let hobbyItems = this.state.hobbies.map((hobby, i) => {
            return <li onClick={this.removeHobby.bind(this)}
                className={cssHobbyItem}
                key={cssHobbyItem + i}>{hobby}</li>;
        });
        let hobbiesLength = this.state.hobbies.length;

        if (hobbiesLength < 3) {
            cssCounter = 'less-three';
        } else if (hobbiesLength === 3) {
            cssCounter = 'equal-three';
        }

        return (
            <div className="hobbies-list">
                <nav className="nav-add">
                    <input type="text" id="input-add" />
                    <button id="new-hobby"
                        onClick={this.addHobby.bind(this)}>New Hobby</button>
                </nav>
                <p>{this.state.deleted && 'Hobby Deleted!'}</p>
                <p className={cssCounter} ><b>Count of Hobbies:
                </b> {this.state.hobbies.length}</p>
                <ul>
                    {hobbyItems}
                </ul>
            </div>
        );
    }
}

export { Hobbies };

// --------- HobbyItem.js ---------------
import React, { Component } from 'react';

class HobbyItem extends React.Component {
    render() {
        return (
            <li></li>
        );
    }
}

export { HobbyItem }

Working Live-Demo

Is it all done in a good way and manner?

What would you do differently and why?

Looking forward to reading your comments and answers.

\$\endgroup\$
2
\$\begingroup\$

Disclaimer: I know sqat about react.js. I only have some minor nitpicks.


When the body of an anonymous function is a single line, instead of ... => { return value; }, you can write more compactly as ... => value, for example here:

let updatedHobbies = this.state.hobbies.filter((hobby) => currentHobby !== hobby);

Although this works, I think it's an unusual writing style, and it would be better to spell it out as an if statement:

!this.state.deleted && this.setState({
    deleted: true
});

When I saw this code, it made me curious what happens for other values of hobbiesLength, that is, what would be in an else block:

if (hobbiesLength < 3) {
    cssCounter = 'less-three';
} else if (hobbiesLength === 3) {
    cssCounter = 'equal-three';
}

The answer to that is a couple of lines higher up:

let cssCounter = 'more-three';

If you move this to the else block, then all the possible values of cssCounter will become easily visible in one place, which will be easier to read and understand.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.