从零开始搭建一个React项目

4,198 阅读8分钟

1.项目准备工作

  • Figma中设计好项目的窗口
  • 安装create-react-app,使用yarn global add create-react-app@3.4.1命令,如果没有安装yarn,可去yarn官网下载msi文件: yarn安装完成后,设置淘宝镜像源:
yarn config set registry https://registry.npm.taobao.org -g

2.使用脚手架创建本地项目

\quad 在项目所在路径,使用create-react-app . --template typescript创建项目,注意:项目名称中不能包括大写字符
命令执行完毕后,可以看到提示: 执行 yarn start命令,yarn就会帮我们打开浏览器窗口,看到我们自己的项目。如下图:

如果觉得每次都会打开一个新的窗口麻烦的话,可以在项目中新增.env文件,在其中加入BROWSER=none 即可阻止弹窗。

2.1 项目目录介说明

\quad 脚手架搭建完毕后,项目目录下自动增加了很多文件,介绍一下文件内容: js,jsx,ts,tsx文件:

  • js - js文件
  • jsx - 支持标签的js文件
  • ts - TypeScript文件
  • tsx - 支持标签的TypeScript文件

入口文件-index.tsx介绍:

TS类型声明文件-react-app-env.d.ts TS配置文件-tsconfig.json

React与Vue对比:

  • 内置功能更少:不自带Router,不自带Redux,不自带SCSS。

3.CSS相关配置

3.1 CSS normalize

根据create-react-app官网提示,在index.css文件中添加@import-normalize;,目的是保证页面在不同浏览器上的默认样式相近。而css-reset则是重置所有的默认样式。

3.2 支持SCSS

支持SCSS官网上给出的答案是用node-sass,但是由于node-sass不好用且经常下载失败,下载后还需要编译后才可使用。所以改为使用dart-sass,但是直接安装dart-sass的话,项目会报错。
如何正确使用scss,根据StackoverFlow的回答,使用:npm install node-sass@npm:dart-sass命令。然后将css文件改为scss之后,可以看到程序也成功运行: 安装前: 安装后:

3.3 import 和JS import优化

在Vue项目中,用@来表示src/目录,而在React中,可以直接用@import 'xxx/yyy' 来引入src/xxx/yyy.scss文件。对于JS文件,需要在jsconfig.json,或者tsconfig.json文件中增加配置:"baseUrl": "src"

3.4 创建helper.scss

\quad 创建helper.scss文件,用于存储变量、函数等共用内容。在helper.scss中写入:$red:#F00;,那么在使用@import "helper"引用了helper.scss的地方,就都可以使用$red代表#F00。这种方式可以推广到组件,使用styled-components实现:
\quad 首先下载styled-components,使用yarn add styled-components@5.0.1(自己指定版本)或者npm install --save styled-components。如果需要在TS中使用,还需要运行yarn add --dev @types/styled-components下载TS支持文件。
\quad 两个必须组件都下载完成后,接下来就可以创建自定义带样式的组件了。创建Button.tsx文件,用于创建自定义的组件:

import styled from 'styled-components'

const Button = styled.button`
  color: red;
  &:hover{
    background: black;
  }
`;

export default Button;

App.tsx中引用该组件:

import React from 'react';
import './App.css';
import Button from "./components/Button";

function App() {
  return (
    <div>
      <Button>按钮</Button>
      <Button>按钮</Button>
      <Button>按钮</Button>
    </div>
  );
}

export default App;

即可在页面上看到三个按钮:

3.5 安装react-router-dom

\quad 根据react-router-dom官网的提示,安装react-router-dom。安装命令:yarn add react-router-dom | npm install react-router-dom。需要支持TS的话,同样需要使用yarn add --dev @types/react-router-dom下载TS支持文件。
\quad 根据React-Router官网的教程,根据实际需要,修改自己的代码。需要设置默认页面,可根据StackoverFlow的回答,使用如下代码:

<Redirect exact from="/" to="default"/>

需要设置404页面,可以根据官网教程,使用如下代码:

 <Route path="*">
    <NoMatch/>
 </Route>

React-Router会从上至下匹配,如果匹配不到就匹配*,可以实现404页面的效果。同时需要注意一点:如果不在Route默认是模糊匹配的。举例:

<Route path="/path">
	<Link>
</Route>
<Route path="/path/path1">
	<Link1/>
</Route>

如果你在其他地方<Link to={'/path/path1'}></Link>,那么它还是会进入到<Link>中,而不是<Link1>。解决方法:根据React_Router的官方提示,可以在<Route>中增加exact关键字。

4.开始项目

4.1 设置中文字体

可直接复制 zenozeng.github.io/fonts.css/ 中代码,对于显示在屏幕上的文字一般用黑体,对于需要打印在纸张上的内容,文字一般用宋体。

4.2 yarn eject & svg-sprite-loader & Tree Shaking

首先矢量图可以去阿里巴巴矢量图库下载svg,我们可以选择使用import将矢量图导入,然后使用<img src="{}">的形式将svg文件当成图片使用。举例:

import chart from 'icons/chart.svg'; //导入

<img src={chart} width={20}></img>; //引用

\quad 但是我们还可以使用更加高级方式引入svg,暨使用svg-sprite-loader。安装方法可以看 github.com/JetBrains/s… 。注意:由于使用svg-sprite-loader需要修改webpack.config.js文件,而使用create-react-app创建的项目中默认是没有webpack相关配置的,所以需要使用yarn eject,执行完该命令后,我们可以看到项目中多出了很多配置文件:

\quad 配置svg-sprite-loader:找到webpack.config.js文件,定位到: module->rules->oneOf,通过注释可以看到此处存在其他loader配置:

github.com/JetBrains/s… 中给出的配置内容复制到oneof下(注意根据自己的webpack版本选择对应的内容),且注意:修改config文件内容需要重启项目。
查看webpack版本: 添加svg-sprite-loader | 以及 svgo-loader (yarn add --dev svgo-loader): 安装并配置后,我们即可在项目中使用svg, 注意:由于TreeShaking的原因,如果我们使用import的方式引入了svg,但是又没有直接引用,那么该部分会从树上被摇下来,所以还是看不到svg。 此时可以使用require引入svg:

require('icons/chart.svg');
require('icons/money.svg');
require('icons/tag.svg');

在需要用到的地方使用svg标签引入:

<svg className='icons'>
    <use xlinkHref='#money'/>
</svg>

对于不同的svg,我们只需要修改xlinkHref属性的名称即可,所以对于这部分我们可以将其封装为组件,减少重复代码。

4.3 封装Icon & importAll & webpack-env

将Icons封装为一个组件:

type Props = {
    name: string;
}

function Icons(props:Props) {
    return (
        <svg className='icons'>
            <use xlinkHref={'#'+props.name}/>
        </svg>
    );
}

export default Icons;

那么可以直接使用<Icons>标签,引入svg:

<Icons name='tag'/>
<Icons name='money'/>
<Icons name='chart'/>

那么问题来了,如何将整个Icon文件夹引入呢?在需要引入svg文件之处添加代码:

let importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext);
try {importAll(require.context('icons', true, /\.svg$/));} catch (error) {console.log(error);}

并根据stackoverflow的回答,安装webpack-env,安装命令:npm install --save-dev @types/webpack-env@1.15.1 | yarn add --dev @types/webpack-env@1.15.1 安装完毕后,我们就不需要一个一个的使用<require>引入svg。

4.4 ReactRouter之activeClassName

\quad 对于导航栏,当我们需要设置用户选中时,该部分导航栏样式改变时,可以根据React-Router的提示,将<Link>标签改为<NavLink>,然后可添加activeClassName属性,设置导航被选中时的样式。
\quad 注意:如果需要修改svg的属性,比如颜色之,由于svg可能自带颜色,所以不一定能修改成功。这时候就需要用到前面引入的svgo-loader,根据svgo-loader的官方文档,在webpack.config.js中配置svgo-loader

                { loader: 'svgo-loader',
                  options: {
                    plugins: [
                      {removeAttrs: {attrs:'fill'}}
                    ]
                  }
                }

修改后重启项目即可。

4.5 抽取重复部分至Layout以及自定义MyLayout

对于项目页面中,存在多个重复样式的部分。我们可以将其抽取到自定义的Layout组件中,通过传入参数的形式,实现将各部分的不同之处展现出来。例如:创建Layout.tsx样式:

function Layout(props:any){
    return(
        <Wrapper>
            <Main className={props.className}>
                {props.children}
            </Main>
            <Nav/>
        </Wrapper>
    );
}

export default Layout;

那么在需要引用的地方,只需使用<Layout>标签:

<Layout>
   <h2>标签1</h2>
</Layout>
<Layout>
   <h2>标签2</h2>
</Layout>

如果需要设置不同的样式,参考styled-componets的文档,可在<Layout>的基础上,再自定义MyLayout:

const MyLayout = styled(Layout)`
  display: flex;
  flex-direction: column;
`
4.6 将Styled Component改造为Funciotn Component

在前面的代码中,大量的使用了:const xxx = style.div`` 定义styled组件。除此之外,我们还可以使用更加高级的Function Component改造Styled,举例:

const TagsSection: React.FunctionComponent = () => {
    return (
        <_TagsSection>
            <ol>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ol>
            <button>增加标签</button>
        </_TagsSection>
    );
};

export default TagsSection;
4.7 React引入classnames库合并className属性

\quad 在前面我们封装了Icons组件,该组件是自带className='icons',那么当我们需要从引用的地方传入这个className时,需要如何实现?引入classnames库。使用命令yarn add --dev classnames如果是ts,则还要加上yarn add -dev @types/classnames,安装完成后,注意package.json中源代码的classnames的版本,以及devDedendencies中的classnames的版本是否一致。

如果不一致,则修改package.json中的版本号,然后使用yarn install生效对package.json的修改。

4.8 引入dayjs库,修改时间样式

使用yarn add dayjs安装dayjs库,在需要更改日期格式的地方直接使用

import dayjs from 'dayjs'

{dayjs(new Date()).format('yyyy年MM月dd日')}

5.须知知识点

5.1 React的OnChange()事件与HTML中的OnChange()事件的触发时机不一样

在HTML中的OnChange事件,会在鼠标移走后触发,而React中,只要输入的内容变化,那么OnChange()时间就会被触发。

5.2 配置过程常见问题

  • 1.使用npm或者yarn安装软件的过程中出现unable to get local issuer certificate? 只需要配置(yarn | npm) config set strict-ssl false

  • 2.parcel build打包项目时,出现Error in parsing SVG: Unbound namespace prefix: "xlink" 根据Github issue,一方面可以在SVG中加入xmls和xmls:link属性:

image.png 不推荐,另一方面可以在命令中加入--no-minify参数,例如parcel build src/index --no-minify

  • 3.React开发者工具安装 安装后重启页面,在F12中可以看到带React样式的标签: 然后就可以看到按自定义的组件划分的页面:

  • 3.build项目并设置GitHub pages 项目完成后,执行yarn build | npm run build命令,将项目打包,打包后的文件一般在项目的build目录下。如下图所示:

这个打包好的文件就是一个独立的网站,只要能启动服务并将其部署,就可以访问。按照build后的提示,使用 yarn global add server 安装服务,安装完成后使用server -s build把build当作根目录启动网站。如下图所示:

  • 4.配置脚本实现自动化部署 由于每次执行yarn build命令,都会导致build目录下的全部内容都被清空,包括隐藏的.git目录,所以每次重新提交build目录都要执行一遍git init | git add . | git commit -v ......。为了避免重复,可将这些命令写到部署脚本中,并把部署脚本写到package.json文件中。如下图: 代码:
#!/usr/bin/env bash

yarn build &&
cd build &&
git add . &&
git commit -m "update build" &&
git init &&
git remote add origin git@github.com:Scott-YuYan/MoreMoney-React-Website.git &&
git push -u origin master -f
cd -

将部署脚本加到package.json中: 这样,只需使用yarn deploy命令,即可执行上述命令。

6.参考文档