CRUD Operations in React - Local State

Summary

This post contains notes on the steps for implementing CRUD operations in React.

Read (Single)


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class MovieList extends React.Component {
    state = {
        movie: {
            title: 'Terminator',
            id: 1
        }
    };

    render () {
        return (
            <ul>
                <Movie  
                    title={this.state.movie.title} 
                    id={this.state.movie.id}  
                />    
            </ul>
        );
    }
}

class Movie extends React.Component {

    render () {
        return (
            <li>{this.props.title}</li>
        );
    }
}

ReactDOM.render(<MovieList />, document.getElementById('content'));

Read (Multiple)


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class MovieList extends React.Component {
    state = {
        movies: [
            {
                title: 'Terminator',
                id: 1
            },
            {
                title: 'Waterboy',
                id: 2
            }
        ]
    };

    render () {
        const movieComponents = this.state.movies.map((movie) => (
            <Movie 
                key={movie.id} 
                title={movie.title} 
                id={movie.id}  
            />
        ));

        return (
            <ul>
                {movieComponents}
            </ul>
        );
    }
}

class Movie extends React.Component {

    render () {
        return (
            <li>{this.props.title}</li>
        );
    }
}

ReactDOM.render(<MovieList />, document.getElementById('content'));



  • Note the difference between Read (Single) vs. Read (Multiple)
    • We declared a variable to store the list of movie components above the return statement.
    • We use the array.map function to loop through the list of movies. array.map will create a "copy" of the array so we don't mutate it by accident.
    • Each movie component must have a unique key value, so we used movie.id
    • The return statement uses the {movieComponents} variable in the JSX

Create


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
class MovieList extends React.Component {
    state = {
        movies: [
            {
                title: 'Terminator',
                id: 1
            },
            {
                title: 'Waterboy',
                id: 2
            }
        ]
    };

    handleFormSubmit = (movie) => {
        this.createMovie(movie);
    };

    createMovie = (movie) => {
        const newMovie = {
            title: movie.title,
            id: uuid.v4()
        };

        this.setState({
            movies: this.state.movies.concat(newMovie),
        });
    };

    render () {
        const movieComponents = this.state.movies.map((movie) => (
            <Movie 
                key={movie.id} 
                title={movie.title} 
                id={movie.id}  
            />
        ));

        return (
            <div>
                <ul>
                    {movieComponents}
                </ul>
                <AddMovieForm 
                    onFormSubmit={this.handleFormSubmit}
                />
            </div>
        );
    }
}

class Movie extends React.Component {

    render () {
        return (
            <li>{this.props.title}</li>
        );
    }
}

class AddMovieForm extends React.Component {
    state = {
        title: this.props.title || ''
    };

    handleTitleChange = (e) => {
        this.setState({ title: e.target.value });
    };

    handleSubmit = () => {
        this.props.onFormSubmit({
            title: this.state.title
        });
        this.setState({ title: '' });
    };

    render () {
        return (
            <div>
                <input
                    type='text'
                    value={this.state.title}
                    onChange={this.handleTitleChange}
                />
                <button onClick={this.handleSubmit}>Submit</button>
            </div>
        );
    }
}

ReactDOM.render(<MovieList />, document.getElementById('content'));

Update


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
class MovieList extends React.Component {
    state = {
        movies: [
            {
                title: 'Terminator',
                id: 1
            },
            {
                title: 'Waterboy',
                id: 2
            }
        ]
    };

    handleFormSubmit = (movie) => {
        this.updateMovie(movie);
    };

    updateMovie = (attrs) => {
        this.setState({
            movies: this.state.movies.map((movie) => {
                if (movie.id === attrs.id) {
                    return Object.assign({}, movie, {
                        title: attrs.title
                    });
                } else {
                    return movie;
                }
            }),
        });
    };

    render () {
        const movieComponents = this.state.movies.map((movie) => (
            <EditableMovie 
                key={movie.id} 
                title={movie.title} 
                id={movie.id}
                onFormSubmit={this.handleFormSubmit}
            />
        ));

        return (
            <div>
                <ul>
                    {movieComponents}
                </ul>
            </div>
        );
    }
}

class EditableMovie extends React.Component {
    state = {
        isEditing: false
    };

    handleEditClick = () => {
        this.setState({ isEditing: true });
    };

    handleFormSubmit = (movie) => {
        this.props.onFormSubmit(movie);
        this.setState({ isEditing: false });
    }

    render () {
        if (this.state.isEditing) {
            return (
                <MovieForm
                    title={this.props.title} 
                    id={this.props.id}
                    onFormSubmit={this.handleFormSubmit}
                />
            );
        } else {
            return (
                <Movie 
                    title={this.props.title} 
                    id={this.props.id}
                    onEditClick={this.handleEditClick}
                />
            );
        }
    }
}

class Movie extends React.Component {
    render () {
        return (
            <li>
                {this.props.title}
                <button onClick={this.props.onEditClick}>Edit</button>
            </li>
        );
    }
}

class MovieForm extends React.Component {
    state = {
        title: this.props.title || ''
    };

    handleTitleChange = (e) => {
        this.setState({ title: e.target.value });
    };

    handleFormSubmit = () => {
        this.props.onFormSubmit({
            id: this.props.id,
            title: this.state.title
        });
    };

    render () {
        return (
            <div>
                <input type="text" value={this.state.title} onChange={this.handleTitleChange} />
                <button onClick={this.handleFormSubmit}>Save</button>
            </div>
        );
    }
}

ReactDOM.render(<MovieList />, document.getElementById('content'));

Delete


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class MovieList extends React.Component {
    state = {
        movies: [
            {
                title: 'Terminator',
                id: 1
            },
            {
                title: 'Waterboy',
                id: 2
            }
        ]
    };

    // Delete is handled here
    handleMovieDelete = (movieId) => {
        this.deleteMovie(movieId);
    };

    deleteMovie = (movieId) => {
        this.setState({
            movies: this.state.movies.filter(m => m.id !== movieId)
        });
    };

    render () {
        const movieComponents = this.state.movies.map((movie) => (

            <Movie 
                key={movie.id} 
                title={movie.title} 
                id={movie.id} 
                onDeleteClick={this.handleMovieDelete}  // Delete handler is passed down here 
            />
        ));

        return (
            <ul>
                {movieComponents}
            </ul>
        );
    }
}

class Movie extends React.Component {
    onDeleteClick = () => {
        this.props.onDeleteClick(this.props.id); // Parent Delete handler is invoked here
    };

    render () {
        return (
            <li>{this.props.title} 
                <button onClick={this.onDeleteClick}>Delete</button>    
            </li>
        );
    }
}

ReactDOM.render(<MovieList />, document.getElementById('content'));

  • The filter function is used to remove an item from state because it will create a "copy" of the array to and return that, which guarantees we don't violate our rule about immutable items within state.
  • I created a separate function for performing the delete, as opposed to putting it in handleMoveDelete so we call deleteMovie from another place if we need to.

No comments:

Post a Comment

} else { }