返回

React初体验:一场网易公开课的旅程

前端

初识React,我选择了网易公开课项目作为起点,通过这个项目,我将带领大家了解React+Ant Design框架的基本用法,以及如何使用react-router-dom来管理数据的持久化。

React简介

React是一个用于构建用户界面的JavaScript库。它使用声明式编程风格,这使得代码更容易阅读和维护。React还支持组件化开发,这使得代码更易于重用。

Ant Design简介

Ant Design是一个基于React的UI框架。它提供了丰富的组件库,涵盖了大部分常见的UI元素,例如按钮、输入框、下拉菜单等。Ant Design的组件设计美观、易于使用,非常适合用于构建现代化的Web应用程序。

项目结构

项目结构如下:

├── src
│   ├── components
│   │   ├── Header.js
│   │   ├── Footer.js
│   │   ├── CourseList.js
│   │   ├── CourseDetail.js
│   │   ├── NotFound.js
│   │   └── ...
│   ├── pages
│   │   ├── Home.js
│   │   ├── Course.js
│   │   ├── NotFound.js
│   │   └── ...
│   ├── App.js
│   ├── index.js
│   └── ...
└── package.json

使用React+Ant Design构建仿网易公开课项目

首先,我们需要安装React和Ant Design的依赖项:

npm install react react-dom antd

然后,我们可以在App.js文件中创建应用程序的根组件:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from './pages/Home';
import Course from './pages/Course';
import NotFound from './pages/NotFound';

const App = () => (
  <Router>
    <Switch>
      <Route exact path="/" component={Home} />
      <Route path="/course/:id" component={Course} />
      <Route component={NotFound} />
    </Switch>
  </Router>
);

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

Home.js文件中,我们可以创建主页组件:

import React from 'react';
import { Layout, Menu, Breadcrumb } from 'antd';
import { Link } from 'react-router-dom';

const { Header, Content, Footer } = Layout;

const Home = () => (
  <Layout>
    <Header>
      <Menu theme="dark" mode="horizontal">
        <Menu.Item key="home"><Link to="/">Home</Link></Menu.Item>
        <Menu.Item key="courses"><Link to="/courses">Courses</Link></Menu.Item>
      </Menu>
    </Header>
    <Content style={{ padding: '0 50px' }}>
      <Breadcrumb style={{ margin: '16px 0' }}>
        <Breadcrumb.Item>Home</Breadcrumb.Item>
      </Breadcrumb>
      <div style={{ background: '#fff', padding: 24, minHeight: 280 }}>
        <h1>Welcome to React + Ant Design</h1>
      </div>
    </Content>
    <Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer>
  </Layout>
);

export default Home;

Course.js文件中,我们可以创建课程详情组件:

import React, { useEffect, useState } from 'react';
import { Layout, Menu, Breadcrumb, Card } from 'antd';
import { useParams } from 'react-router-dom';

const { Header, Content, Footer } = Layout;

const Course = () => {
  const { id } = useParams();
  const [course, setCourse] = useState(null);

  useEffect(() => {
    // 这里假设我们有一个API,可以根据id获取课程信息
    fetch(`api/courses/${id}`).then(res => res.json()).then(data => setCourse(data));
  }, [id]);

  if (!course) {
    return <div>Loading...</div>;
  }

  return (
    <Layout>
      <Header>
        <Menu theme="dark" mode="horizontal">
          <Menu.Item key="home"><Link to="/">Home</Link></Menu.Item>
          <Menu.Item key="courses"><Link to="/courses">Courses</Link></Menu.Item>
        </Menu>
      </Header>
      <Content style={{ padding: '0 50px' }}>
        <Breadcrumb style={{ margin: '16px 0' }}>
          <Breadcrumb.Item>Home</Breadcrumb.Item>
          <Breadcrumb.Item><Link to="/courses">Courses</Link></Breadcrumb.Item>
          <Breadcrumb.Item>{course.title}</Breadcrumb.Item>
        </Breadcrumb>
        <div style={{ background: '#fff', padding: 24, minHeight: 280 }}>
          <Card title={course.title}>
            <p>{course.description}</p>
          </Card>
        </div>
      </Content>
      <Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer>
    </Layout>
  );
};

export default Course;

NotFound.js文件中,我们可以创建404页面组件:

import React from 'react';
import { Layout, Menu, Breadcrumb } from 'antd';
import { Link } from 'react-router-dom';

const { Header, Content, Footer } = Layout;

const NotFound = () => (
  <Layout>
    <Header>
      <Menu theme="dark" mode="horizontal">
        <Menu.Item key="home"><Link to="/">Home</Link></Menu.Item>
        <Menu.Item key="courses"><Link to="/courses">Courses</Link></Menu.Item>
      </Menu>
    </Header>
    <Content style={{ padding: '0 50px' }}>
      <Breadcrumb style={{ margin: '16px 0' }}>
        <Breadcrumb.Item>Home</Breadcrumb.Item>
        <Breadcrumb.Item>404</Breadcrumb.Item>
      </Breadcrumb>
      <div style={{ background: '#fff', padding: 24, minHeight: 280 }}>
        <h1>404 Not Found</h1>
      </div>
    </Content>
    <Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer>
  </Layout>
);

export default NotFound;

最后,我们需要在index.js文件中启动应用程序:

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

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

使用react-router-dom来管理数据的持久化

在项目中,我使用了react-redux来管理数据的状态,但是并没有连接数据库,所以界面一刷新,store里面的state就全部清零了。这导致我一开始用location跳转就一直保存不了数据,纠结了半天,于是就百度了一下,最后发现可以使用react-router-dom来解决这个问题。

具体做法如下:

  1. App.js文件中,使用useHistory钩子获取历史记录对象:
import { useHistory } from 'react-router-dom';

const App = () => {
  const history = useHistory();

  // ...

  return (
    // ...
  );
};
  1. 在组件中,使用history.push方法来跳转到指定路由,并传递数据:
import { useHistory } from 'react-router-dom';

const Course = () => {
  const history = useHistory();

  const handleClick = () => {
    history.push('/course/123', { data: 'hello world' });
  };

  // ...

  return (
    // ...
  );
};
  1. 在目标组件中,使用useLocation钩子获取当前位置对象,然后使用location.state属性来获取传递的数据:
import { useLocation } from 'react-router-dom';

const CourseDetail = () => {
  const location = useLocation();

  const data = location.state.data;

  // ...

  return (
    // ...
  );
};

这样,我们就