以下内容算是对第一个 react 项目「纸记卡片 Paper MEMO」的一些技术总结,都是最基本的,部分内容可能另起文章记录,以备忘。
开始
首先安装 node.js,它是一个 exe 文件,直接从官网下载下来傻瓜安装即可。安装完成后打开 cmd 安装create-react-app
:
npm i -g create-react-app
安装 VS Code 并安装两个插件:
- Prettier – Code formatter(用来格式化代码)
- Simple React Snippets (用来专门补全 react 的代码)
在想要新建项目的文件夹打开 cmd,新建 react 项目,比如说这个项目叫做 react-app:
Create-react-app react-app
一些常用的命令,这些命令需要在项目文件夹下打开 cmd 运行:
npm start #预览项目
npm run build #编译成用于生产环境的静态文件
例如运行npm start
后浏览器会自动打开http://localhost:3000
,可以预览。而运行npm run build
可以生成用于生产环境的文件,这些文件会在build
文件夹下,将这些文件上传到服务器
或者虚拟主机
均可。
以「纸记卡片 Paper MEMO」为例
「纸记卡片 Paper MEMO」项目中,除了开始
的操作之外,还需要在环境中准备:(使用`npm install`批量安装依赖)
npm install @material-ui/core
npm install @material-ui/icons
npm install redux
npm install react-redux
npm install --save jspdf
npm install --save react-dropzone
「纸记卡片 Paper MEMO」项目使用了 Material-UI 组件库(下方涉及到样式库均为 Material-UI),其中使用了其默认的Dashboard 模板进行改造。src
下的目录结构如下所示:
-src
--CreatPdf
---Pdf2.js
---Pdf4.js
---Pdf8.js
---Pdf16.js
---Pdf32.js
--Ppmemo
---Dashboard.js
---Emoji.js
---Helper.js
---listItems.js
---Title.js
--font
---font.js
--images
--store
---reducer.js
import 导入
以下是一些头部导入的示例:
//每次必须的
import React from "react";
//当需要用到useCallback和useEffect时
import React, { useCallback, useEffect } from "react";
//导入material-ui的组件
import Drawer from "@material-ui/core/Drawer";
//可以对组件的样式进行定制
import { makeStyles } from "@material-ui/core/styles";
//导入material-ui的icon
import MenuIcon from "@material-ui/icons/Menu";
//导入自己的组件
import Helper from "./Helper";
//导入自己的图片
import conjHelper from "../images/conjHelper.jpg";
makeStyles 和基础结构
Material-UI 中使用自定义样式时,需要先导入makeStyles
。一个 react 的基本结构(react hooks)也如下所示:
- 开始的时候使用
import
导入。 - function 函数可以放一些自己想做的事情。
- makeStyle 自定义样式(仅限 Material-UI)。
export default function Upload() {}
可以理解为主函数,必不可少。
//可以对组件的样式进行定制
import { makeStyles } from "@material-ui/core/styles";
import Helper from "./Helper";
function Copyright() {
//做一些想做的事情
return (//返回一些想返回的东西)
}
const useStyles = makeStyles(() => ({
text: {
textAlign: "center",
position: "relative",
top: "40%",
},
}));
export default function Upload() {
const classes = useStyles();
return (
<div>
<Paper className={classes.text}>
<Helper/>
<Copyright />
</Paper>
</div>
}
switch
switch 比较常用,可以代替大量的if else
,但是注意不要忘了default
,用于默认返回一些东西:
function getStepContent(stepIndex) {
switch (stepIndex) {
case 0:
return "阅读上述准备步骤后,点击下一步";
case 1:
return "选择一份文件并上传(当且仅当上传符合条件的txt文件后,才能进行下一步)";
case 2:
return "调整纸张设置并生成卡片,点击“下载”获得PDF文件";
case 3:
return "";
default:
return "Unknown stepIndex";
}
}
按钮和判断
在下方的例子中:
- 当
successedData
为 false 时(注意需要使用全等===
),按钮不可用。 - 当用户点击按钮时
onClick
,执行handleNext
。
export default function Dashboard() {
const handleNext = () => {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
};
return (
<Button
variant="contained"
color="primary"
onClick={handleNext}
className={classes.buttonArea}
disabled={successedData === false}
>
{activeStep === steps.length - 1 ? "下载" : "下一步"}
</Button>
);
}
下方是另一种判断的使用方式:
<div className={classes.fixedHeight100}>
{activeStep === steps.length ? <div></div> : <div></div>}
</div>
React 懒加载
打开的网页的一开始可能不需要加载所有的网站内容,这样可以节省加载时间,所以这里需要使用懒加载。
- 下方的
import
写在开头那堆 import 文件下方,凡是不能和正常的 import 文件混起来写。 React.Suspense
可以写一些在等待懒加载时所加载的一些提示语、进度条等。
const Pdf2 = React.lazy(() => import("../CreatePdf/Pdf2"));
const CreatPdf = () => {
return (
<React.Suspense
fallback={
<div>
<CircularProgress />
<Typography variant="h6">等待下载中...这可能需要一些时间</Typography>
</div>
}
>
<Pdf2 />
</React.Suspense>
);
};
setState
setState
用的比较多,用来更新 ui 上显示的数据。
- 有个变量叫
Successed
,初始值为""
。 - 当
displayUploadData
等于undefined
时,将Successed
的值设为"❌文件不符合要求"
。
const [Successed, setSuccessed] = React.useState("");
if (displayUploadData === undefined) {
setSuccessed("❌文件不符合要求");
}
- 有个变量叫
format
,初始值为一个对象。 handleChangeFormat
函数中将 format 里面的 format 设置为一个别的值。- 和上面的例子一样,
setFormat
会设置原有format对象
里所有的值,但是要注意写法。
const [format, setFormat] = React.useState({
format: "Pdf16",
font: "fontFz",
fontSizeA: "fontMiddle",
fontSizeB: "fontMiddle",
cardNum: true,
});
const handleChangeFormat = (event) => {
format.format = event.target.value;
setFormat({ ...format }); //就是要写成这样,不然无法更新;这样format就变为了event.target.value里的值
};
显示图片
//导入自己的图片
import conjHelper from "../images/conjHelper.jpg";
<img src={conjHelper} alt="" className={classes.imageStyle} />;
redux 和 react-redux
假设文件目录如下:
-src
--CreatPdf
---Pdf2.js
--Ppmemo
---Dashboard.js
---Emoji.js
---Upload.js //从这里传数据
--font
---font.js
--images
--store //新建
---reducer.js //新建
首先在根目录新建一个文件夹和文件叫做store/reducer.js
,该文件内的内容如下:
const initialState = {
content: "欢迎使用ppmemo-https://xd.sh.cn",
format: {
format: "Pdf16",
font: "fontFz",
fontSizeA: "fontMiddle",
fontSizeB: "fontMiddle",
cardNum: true,
},
successedData: false,
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case "ADD_FORMAT": {
const newTemp = action.format;
return {
...state,
format: newTemp,
};
}
case "ADD_CONTENT": {
const newTemp = action.content;
return {
...state,
content: newTemp,
};
}
default:
return state; //在 default 情况下返回旧的 state。遇到未知的 action 时,一定要返回旧的 state。
}
};
export default reducer;
在组件文件Upload.js
中导入:
import { useDispatch } from "react-redux"; //新版里导入useDispatch和useSeletor
// 用 useDispatch 產生 dispatch 方法,dispatch用来给reducer送数据
const dispatch = useDispatch();
const storeUploadData = (uploadData) => {
dispatch({
type: "ADD_CONTENT",
content: uploadData,
});
};
//使用上述函数
storeUploadData(uploadData);
如果更新的是对象,比如上文中的format
就有5个对象元素,更新其中的font
:
const dispatch = useDispatch();
const storeFormat = (format) => {
// 用法一樣
dispatch({
type: "ADD_FORMAT",
format: format,
});
};
//使用上述函数,比方说更新对象format中的font
const handleChangeFont = (event) => {
format.font = event.target.value;
setFormat({ ...format }); //就是要写成这样,不然无法更新
storeFormat(format);
};
react hooks
【待更新】
jsPDF
【待更新】
react-dropzone
【待更新】
真的也有人想到了这种方式做卡片,而不是APP背诵
太阳下面真的没有新鲜事呀
谢谢站长的分享,对技术小白莫大的帮助
我是用来作为软件背诵的补充的,先用supermemo筛选出难的,再打出来手卡背诵,毕竟只是打印手卡的话很难做到科学复习。