概要
这里跟着mosh学习react入门, 整个视频比较基础,涉及到ES6, React类组件、函数式组件、Hook的入门,状态上移。 我看mosh的视频收获最大的就是他的编程思路,比如组件,一般他会先设计组件接口,也就是函数的输入输出,先设计接口参数, 这样划分接口职责。
系统截图
组件结构设计
其中用到的知识点
ES6 解构赋值
const {movies, sortColumn, onDelete, onSort, onLike} = this.props;
对象扩展
const sortColumn = {...this.props.sortColumn}
数组扩展
const movies = [...this.state.moves]
loadash 分页、排序
slice
take
orderBy
样式
样式用到了bootstrap table样式, listGroup样式, 点赞样式使用了font-awesome样式。
关键代码片段
import React, { Component } from "react";
import { getMovies } from "../services/fakeMoviesService";
import { getGenres } from "../services/fakeGenreService";
import MoviesTable from "./moviesTable";
import Pagination from "./pagination";
import { paginate } from "../utils/paginate";
import ListGroup from "./listGroup";
import _ from "lodash";
class Movies extends Component {
state = {
movies: [],
genres: [],
currentPage: 1,
pageSize: 4,
sortColumn: { path: "title", order: "asc" },
};
componentDidMount() {
const genres = [{ name: "All Genres", _id: "" }, ...getGenres()];
this.setState({ movies: getMovies(), genres: genres });
}
handleLike = (movie) => {
const movies = [...this.state.movies];
const index = movies.indexOf(movie);
movies[index] = { ...movies[index] };
movies[index].liked = !movies[index].liked;
this.setState({ movies });
};
handleDelete = (id) => {
const movies = [...this.state.movies].filter((x) => x._id !== id);
this.setState({ movies });
};
handlePageChange = (page) => {
this.setState({ currentPage: page });
};
handleGenreSelect = (genre) => {
this.setState({ selectedGenre: genre, currentPage: 1 });
};
handleSort = (sortColumn) => {
this.setState({ sortColumn });
};
render() {
const {
movies,
genres,
currentPage,
pageSize,
selectedGenre,
sortColumn,
} = this.state;
const filtered =
selectedGenre && selectedGenre._id
? movies.filter((m) => m.genre._id === selectedGenre._id)
: movies;
const sorted = _.orderBy(filtered, [sortColumn.path], [sortColumn.order]);
const newMovies = paginate(sorted, currentPage, pageSize);
return (
<div className="row">
<div className="col-3">
<ListGroup
items={genres}
selectedItem={selectedGenre}
onItemSelect={this.handleGenreSelect}
/>
</div>
<div className="col">
<p>Showing {filtered.length} movies in the database</p>
<MoviesTable
movies={newMovies}
onLike={this.handleLike}
onDelete={this.handleDelete}
onSort={this.handleSort}
sortColumn={this.state.sortColumn}
/>
<Pagination
itemsCount={filtered.length}
currentPage={currentPage}
pageSize={pageSize}
onPageChange={this.handlePageChange}
/>
</div>
</div>
);
}
}
export default Movies;
import React, { Component } from "react";
import Like from "./like";
import TableHeader from "./tableHeader";
class MoviesTable extends Component {
render() {
const { movies, onLike, onDelete, sortColumn, onSort } = this.props;
const columns = [
{ path: "title", label: "Title" },
{ path: "genre.name", label: "Genre" },
{ path: "numberInStock", label: "Stock" },
{ path: "dailyRentalRate", label: "Rate" },
{ key: "like" },
{ key: "delete" },
];
return (
<table className="table">
<TableHeader
columns={columns}
sortColumn={sortColumn}
onSort={onSort}
/>
<tbody>
{movies.map((movie) => (
<tr key={movie._id}>
<td>{movie.title}</td>
<td>{movie.genre.name}</td>
<td>{movie.numberInStock}</td>
<td>{movie.dailyRentalRate}</td>
<td>
<Like liked={movie.liked} onClick={() => onLike(movie)} />
</td>
<td>
<button
onClick={() => onDelete(movie._id)}
className="btn btn-danger btn-sm"
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
);
}
}
export default MoviesTable;
import React, { Component } from "react";
/**
* 接口三个参数
* columns: array,
* onSort: function,
* sortColumn: object
* **/
class TableHeader extends Component {
raiseSort = (path) => {
const sortColumn = { ...this.props.sortColumn };
if (sortColumn.path === path) {
sortColumn.order = sortColumn.order === "asc" ? "desc" : "asc";
} else {
sortColumn.path = path;
sortColumn.order = "asc";
}
this.props.onSort(sortColumn);
};
render() {
return (
<thead>
<tr>
{this.props.columns.map((column) => (
<th
key={column.path || column.key}
onClick={() => this.raiseSort(column.path)}
>
{column.label}
</th>
))}
</tr>
</thead>
);
}
}
export default TableHeader;
import React, { Component } from "react";
const ListGroup = ({
items,
textProperty,
valueProperty,
selectedItem,
onItemSelect,
}) => {
return (
<ul className="list-group">
{items.map((item) => (
<li
key={item[valueProperty]}
className={
selectedItem === item ? "list-group-item active" : "list-group-item"
}
onClick={() => onItemSelect(item)}
>
{item[textProperty]}
</li>
))}
</ul>
);
};
ListGroup.defaultProps = {
textProperty: "name",
valueProperty: "_id",
};
export default ListGroup;
import React, { Component } from "react";
const Like = ({ onClick, liked }) => {
return (
<i
onClick={onClick}
style={{ cursor: "pointer" }}
className={liked ? "fa fa-heart" : "fa fa-heart-o"}
aria-hidden="true"
/>
);
};
export default Like;
代码地址:gitee.com/garfieldzf/… 视频地址:www.bilibili.com/video/BV1Sb…