跟着Mosh学习React

473 阅读2分钟

概要

这里跟着mosh学习react入门, 整个视频比较基础,涉及到ES6, React类组件、函数式组件、Hook的入门,状态上移。 我看mosh的视频收获最大的就是他的编程思路,比如组件,一般他会先设计组件接口,也就是函数的输入输出,先设计接口参数, 这样划分接口职责。

系统截图

截屏2022-11-27 11.49.41.png 截屏2022-11-27 11.49.46.png截屏2022-11-27 11.49.56.png

组件结构设计

截屏2022-11-27 11.54.24.png

其中用到的知识点

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…