Git Product home page Git Product logo

loginweb-with-react's People

Contributors

brancelee avatar

Stargazers

 avatar

Watchers

 avatar

loginweb-with-react's Issues

this.setState

更新并执行操作??

How to understand the arrow function in the setState

			this.setState(
				{
					gameState: newGameState
				},
				() => {
					this.runCode();
				}
			);

Redux的一些总结

Redux 状态管理器

image

  • Redux是将整个应用状态存储到到一个地方,称为store里面保存一棵状态树(state tree)

  • 组件可以派发(dispatch)行为(action)给store,而不是直接通知其它组件

  • 其它组件可以通过订阅store中的状态(state)来刷新自己的视图.

function createStore() {
  let state;
  let listeners = [];
  
 function getState() {
   return JSON.parse(JSON.stringify(state))
 }
 
 function dispatch(action) { // 分发
   state = reducer(state,action); // 接收当前 State 和Action作为参数,返回一个新的 State
   listeners.forEach(listener => listener()) // 一旦状态改变,触发所有的监听函数,这里需要优化,只有相关状态改变才需要触发
 }
 
 function subscribe(listener){ // 订阅,如果需监听状态变化,将监听函数传过来
    listeners.push(listener); // 保存监听函数到监听数组
    return function () { // 返回取消订阅的函数
      listeners = listeners.filter(item => item != listener); // 过滤监听函数
    }
 }
 
 dispatch({ type: '@@INIT' }); // 在创建仓库的时候,初始化state的值
 
 return {
   getState,
   dispatch,
   subscribe
 }
 
}

这里是分割线,上面一部分是仓库定义,下面部分是使用方法

let initState = {
  count: 0
}
//处理器,接收二个参数 ,接收老状态和action,返回新状态 
function reducer(state = initState, action) { // 如果state没有值,默认值为initState
   //判断动作的类型
   switch (action.type) {
       case 'ADD_TODO': 
           return { ...state, count: action.number }; //...state解构state所有属性,count: action.number覆盖前面的值
       default:
           return state;
   }
}
let store = createStore()  // 创建一个仓库

let action = { // 定义一个action
 type: 'ADD_TODO',
 number: 1
};

let unADD = store.subscribe(function(){ // 监听状态改变
  console.log('状态改变了,现在的state为:')  // 状态改变了,现在的state为:
  console.log(store.getState()) // { count: 1 }
})

store.dispatch(action);  // 派发一个action,改变state的状态

前端采坑路合集

前端采坑路合集(踩得不少)

掘金
首页
JserWang
2018年08月13日阅读 6903
前端工程不了解?带你踩坑加爬坑。
本文希望能帮助那些一直用脚手架而对工程化没有概念的朋友。

文中许多步骤会在运行时报错,从错误中分析需要添加的配置,加深印象以及对所添加的每一行配置的理解。

本文将以React为例,带你走一次。

创建目录
mkdir demo && cd demo
npm init
touch index.js
复制代码
webpack
安装webpack依赖
yarn add webpack webpack-cli --dev # 安装webpack相关依赖
touch webpack.config.js # 新建webapck配置文件
复制代码
修改配置
这是一份最基本的webpack配置:

const path = require('path');

module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};
复制代码
调整package.json
在package.json中,添加scipts如下:

"scripts": {
"build": "webpack"
},
复制代码
初试build
在命令行中执行

npm run build
复制代码
你会看到如下警告:

WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: webpack.js.org/concepts/mo…

由于webpack在4.0后,新增mode配置项,它为我们默认设置了production。但是该警告并没有影响build的结果暂且忽略。 可以看到dist目录已经生成了名为my-first-webpack.bundle.js文件。

OK,最基本的配置已经完成,接下来引入React。

React
安装react依赖
yarn add react react-dom # 安装react相关依赖
复制代码
使用
在使用前,需要在dist目录中,添加index.html,内容如下:

<title>React</title>
<script src="./my-first-webpack.bundle.js"></script>

复制代码
从react官网官网找段HelloWorld贴过来吧,全英文看不懂?没关系,代码你总认识吧,贴就完了!

将index.js中的内容变更如下:

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(

Hello, world!

, document.getElementById('root') ); 复制代码 OK,看似完美,执行下,build看看效果。

ERROR in ./index.js 4:16
Module parse failed: Unexpected token (4:16)
You may need an appropriate loader to handle this file type.
| import ReactDOM from 'react-dom';
|

ReactDOM.render(

Hello World
,
| document.getElementById('root'));
复制代码
报错了?莫慌,从错误信息中找关键字,You may need an appropriate loader to handle this file type.。 这时候感慨一句,程序员是伟大的,错误信息很详细了,告诉我们需要适当的loader来处理这个文件。什么loader?别问我,不是我干的,继续往下看刚才的链接下一小节react-jsx的介绍,拉到最下面,是不是有一段关于官方的建议?继续查找关键字,是不是看到一个叫Babel的东西?纳尼,莫非jsx和它有关系?虽然这段话是说推荐编辑器设置的吧,但是程序员必备一颗好奇的心。

Babel
Google一下上面的关键词Babel,进去瞅瞅吧。 于是开始接触一个新名词Babel,这玩意干啥的?能为我们带来什么?看看首页吧。

ES2015 及更高版本

Babel 通过语法转换器支持最新版本的 JavaScript 。

Polyfill

由于 Babel 只转换语法(如箭头函数), 你可以使用 babel-polyfill 支持新的全局变量,例如 Promise 、新的原生方法。

JSX 和 Flow

Babel 能够转换 JSX 语法并去除类型注释。

可插拔

Babel 是建立在插件之外的。 你可以使用已有的插件或者自己编写插件来组成属于你自己的转换管道。

可调式

支持 Source map 因此可以轻松调试编译后代码。

看完首页的介绍,是否和我有同样的感叹:好东西啊!既然是好东西,用起来吧。 从配置的webpack选项中,你会发现刚才出现的两个关键字都来了babel、loader,艾玛,得来全不费工夫。

yarn add babel-loader babel-core babel-preset-env babel-polyfill babel-preset-react --dev

这波安装比较长?因为我们把刚才看到的es2015、更高版本语法的,polyfill,jsx的都装上了

复制代码
通过config配置
将webpack.config.js修改配置如下:

const path = require('path');

module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
}
};
复制代码
创建.babelrc配置文件
touch .babelrc #创建.babelrc
复制代码
将以下内容粘贴至.babelrc中:

{
"presets": ["env", "react"]
}
复制代码
至此,已经将上面的babel-preset-env、babel-preset-react使用上了,那polyfill怎么用呢?继续看波文档吧。emmm,写的很清楚了,我们把polyfill使用上吧,修改webpack.config.js中的配置如下:

const path = require('path');

module.exports = {
entry: ["babel-polyfill", "./index.js"],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
}
};
复制代码
该配置的都配置完了,执行下npm run build看看效果?果不其然,编译过了。

你以为工程就这样配完了吗?NO,这仅仅是个开始!

react-router
SPA工程中使用,什么是SPA,单页应用?什么是单页应用?只有一个html,公用js css仅引用一次,通过局部刷新渲染的应用。

react-router官网,按着快速上手的步骤来。

安装
yarn add react-router-dom
复制代码
使用
Now you can copy/paste any of the examples into src/App.js. Here’s the basic one:

这里从create-react-app中使用方式,虽然我们不是,但是我们自己搭的也不差啊。自己建个src和App.js吧。

mkdir src && touch src/App.js
复制代码
将官方的🌰贴进来App.js:

import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'

const Home = () => (

Home

)

const About = () => (

About

)

const Topic = ({ match }) => (

{match.params.topicId}

)

const Topics = ({ match }) => (

Topics

  • Rendering with React
  • Components
  • Props v. State
<Route path={`${match.path}/:topicId`} component={Topic}/>
<Route exact path={match.path} render={() => (
  <h3>Please select a topic.</h3>
)}/>
)

const BasicExample = () => (



  • Home

  • About

  • Topics

  <hr/>

  <Route exact path="/" component={Home}/>
  <Route path="/about" component={About}/>
  <Route path="/topics" component={Topics}/>
</div>
) export default BasicExample 复制代码 接下来在index.js中引用:

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

ReactDOM.render(
,
document.getElementById('root')
);
复制代码
执行npm run build看看。没报错,使用浏览器打开dist/index.html看看。点击链接没反应?什么情况?莫慌,打开控制台看看:

Uncaught DOMException: Failed to execute 'pushState' on 'History': A history state object with URL 'file:///' cannot be created in a document with origin 'null' and URL

emmmm,咋整?别问我,真不是我干的… 既然chrome不好使,就再看一眼safari下好不好用吧,一样不好使,再看一眼报错信息。

[Error] SecurityError: Blocked attempt to use history.pushState() to change session history URL from file:///demo/dist/index.html to file:///about. Paths and fragments must match for a sandboxed document.

好像safari的报错更友好一些,我们可以清楚的看到,它在试图改变链接,为了安全起见,你认为这么做合理么?岂不是拿个html能访问计算机任何文件了?emmm,果然不合理。再看关键词: Paths and fragments must match for a sandboxed document。

那我们就构建个沙盒环境吧。

webpack-dev-server
配置参考链接

安装
yarn add webpack-dev-server --dev
复制代码
修改配置
在package.json中添加scripts:

"dev": "webpack-dev-server"
复制代码
在webpack.config.js根节点中,添加:

devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000
}
复制代码
执行上面刚添加的srcripts:

npm run dev
复制代码
浏览器中打开链接localhost:9000

功能没问题,样式没法忍,有木有?改!

在src中新建app.css文件,新增如下内容:

.container {
list-style: none;
}
复制代码
在App.js中,添加如下代码:

import './app.css';
复制代码
将BasicExample中的ul应用样式:

  • Home
  • About
  • Topics
复制代码 这时,你会发现一个熟悉的错误。

You may need an appropriate loader to handle this file type.

这次我们可以很快的定位到,缺少加载css相关的loader。

再次与loader相遇
webpack相关文档 虽然,webpack的文档总是那么的不及时,但是一些基础性的东西,还是能从中学到的。既然又一次遇到了loader,不妨这次我们就彻底搞明白什么是loader,它为我们提供了什么?

loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!

看完这么长一段,我总结了一句话,通过import来处理的文件,需要对应的loader。既然如此,那就一个一个安吧。

css-loader
安装
yarn add style-loader css-loader --dev
复制代码
配置
修改webpack.config.js中,module下的rules,就像添加babel-loader一样,添加如下配置:

{
test: /.css$/,
use: [
'style-loader',
'css-loader'
]
}
复制代码
关于css-loader这里要再多提一句,当你不想对全局css进行污染,想通过以下方式使用时:

import styles from 'app.css';

复制代码 请使用css module,webpack配置css module的方式也十分简单:

'css-loader?modules&localIdentName=[name]-[hash:base64:5]',
复制代码
将 css-loader调整成以上内容即可。

file-loader
处理各种图标、图片文件

安装
yarn add file-loader --dev
复制代码
配置
修改webpack.config.js中,module下的rules,添加如下配置:

{
test: /.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
复制代码
字体文件依旧由file-loader处理,继续添加配置:

{
test: /.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
复制代码
loader暂时添加到这里,这时记住了没?想让webpack处理对应文件,就要有对应的loader。

继续刷新看我们的demo工程,生效了。

初识Plugin
loader配置完,继续按着文档来吧,看看我们还有什么可以了解的。

插件是 webpack 的支柱功能。webpack 自身也是构建于,你在 webpack 配置中用到的相同的插件系统之上!

插件目的在于解决 loader 无法实现的其他事。

html-webpack-plugin
管理输出中有这么一段:

如果我们更改了我们的一个入口起点的名称,甚至添加了一个新的名称,会发生什么?生成的包将被重命名在一个构建中,但是我们的index.html文件仍然会引用旧的名字。我们用 HtmlWebpackPlugin 来解决这个问题。

OK,了解了它的目的,有用,装!

安装
yarn add html-webpack-plugin --dev

复制代码
配置
在webpack.config.js的根节点中添加plugins:

// 引入html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
复制代码
plugins: [
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
复制代码
重启下npm run dev,你会发现页面空白了?卧槽,这不是坑么?打开控制台看一眼,Target container is not a DOM element.,再看一眼Elements选项卡中的内容,发现,咦。好像我们的

神奇的消失了。 再看文档,发现这么一句话:

如果你想要了解更多 HtmlWebpackPlugin 插件提供的全部功能和选项,那么你就应该多多熟悉 HtmlWebpackPlugin 仓库。 其中的配置项中,template这项是这么描述的: webpack require path to the template. Please see the docs for details

模板啊,我们把dist/index.html中的文件挪出来,放到项目的根目录下,然后再修改下webpack.config.js中的配置:

new HtmlWebpackPlugin({
title: 'Demo',
template: './index.html'
})
复制代码
重启下服务看看吧,npm run dev

页面出来了,但是报了个错:only one instance of babel-polyfill is allowed。 这又是什么错?我们明明只有一个entry,为什么说引了多次呢?打开Elements选项卡中,惊奇的发现,原来是我们刚才直接从dist目录中挪的index.html中,还存在<script src="./my-first-webpack.bundle.js"></script>这么一段script,删掉,再重启。大功告成。

clean-webpack-plugin
你可能已经注意到,由于过去的指南和代码示例遗留下来,导致我们的 /dist 文件夹相当杂乱。webpack 会生成文件,然后将这些文件放置在 /dist 文件夹中,但是 webpack 无法追踪到哪些文件是实际在项目中用到的。

依然有用,依然装!

安装
yarn add clean-webpack-plugin --dev
复制代码
配置
修改webpack.config.js: 引入CleanWebpackPlugin:

const CleanWebpackPlugin = require('clean-webpack-plugin');
复制代码
添加plugins:

new CleanWebpackPlugin(['dist']),
复制代码
区分生产环境与开发环境
为什么要区分生产环境与开发环境?

开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source map 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。

拆分webpack配置
按照官方教程,来进行拆分。在此,我更推荐新建config目录,将配置统一放置config中,所以此时我们的配置文件应该是:

config/webpack.common.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
entry: ["babel-polyfill", "./index.js"],
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].[contenthash:12].js'
},
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
loader: "babel-loader?cacheDirectory"
},
{
test: /.css$/,
use: [
'style-loader',
"css-loader"
]
},
{
test: /.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
]
},
plugins: [
new CleanWebpackPlugin(["dist"], {
root: path.resolve(__dirname, "../"),
}),
new HtmlWebpackPlugin({
title: 'Demo',
template: './index.html'
})
]
};
复制代码
config/webpack.dev.js:

const merge = require('webpack-merge');
const common = require('./webpack.common');
const path = require('path');

module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve(__dirname, '../dist'),
compress: true,
port: 9000
}
});
复制代码
config/webpack.prod.js:

const merge = require('webpack-merge');
const common = require('./webpack.common');

module.exports = merge(common, {
mode: 'production',
});
复制代码
另外,package.json中的scripts也要进行相应的调整:

"build": "webpack --config config/webpack.prod.js",
"dev": "webpack-dev-server --config config/webpack.dev.js"
复制代码
关于分离css
extract-text-webpack-plugin【4.0已废弃】
tips: 这是一个从入门到放弃的Plugin,感兴趣的话可以继续跟着操作,没兴趣请跳至下个小节。

它会将所有的入口 chunk(entry chunks)中引用的 *.css,移动到独立分离的 CSS 文件。

安装
yarn add extract-text-webpack-plugin --dev
复制代码
配置
照着文档中的🌰把配置贴进来,修为webpack.config.js:

const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
mode: "production",
entry: ["babel-polyfill", "./index.js"],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
loader: "babel-loader?cacheDirectory"
},
{
test: /.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
],
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000
}
};
复制代码
重启服务的时候,你会发现报错了?WTF?费了半天劲,结果还不能用?这时候我们需要注意一点,就是它曾经肯定是能用的,不然不能放到文档上,这就体现出来webpack文档落后了。既然如此,因为我们当下使用的是webpack 4.x的版本,这时候先去ExtractTextWebpackPlugin的github上搜搜有没有想过issue吧,关键词webpack 4。 看到一个issue。

@vasivas don't use extract-text-webpack-plugin for extract css, please use github.com/webpack-con…

竟然还有这种操作,那就看看这个mini-css-extract-plugin。

关于webpack,就引导到这里,本文不是对webpack进行讲解,更多关于webpack的部分,可以看: @花裤衩 写的文章:

手摸手,带你用合理的姿势使用webpack4(上)

手摸手,带你用合理的姿势使用webpack4(下)

最终我们关于分离css的内容变成如下: webpack.common.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
entry: ["babel-polyfill", "./index.js"],
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].[contenthash:12].js'
},
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
loader: "babel-loader?cacheDirectory"
},
{
test: /.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader?modules&localIdentName=[name]-[hash:base64:5]',
]
},
{
test: /.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
]
},
plugins: [
new CleanWebpackPlugin(["dist"], {
root: path.resolve(__dirname, "../"),
}),
new HtmlWebpackPlugin({
title: 'Demo',
template: './index.html'
}),
]
};
复制代码
webpack.prod.js:

const merge = require('webpack-merge');
const common = require('./webpack.common');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = merge(common, {
mode: 'production',
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCSSAssetsPlugin({}) // use OptimizeCSSAssetsPlugin
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash:12].css',
chunkFilename: '[name].[contenthash:12].css' // use contenthash *
})
]
});
复制代码
webpack.dev.js:

const merge = require('webpack-merge');
const common = require('./webpack.common');
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve(__dirname, '../dist'),
compress: true,
port: 9000
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
}),
]
});
复制代码
代码分离
依旧看上面 @花裤衩 的文章,分的很细腻。在此我们简单分离:

在webpack.common.js中修改:

const merge = require('webpack-merge');
const common = require('./webpack.common');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = merge(common, {
mode: 'production',
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCSSAssetsPlugin({}) // use OptimizeCSSAssetsPlugin
],
runtimeChunk: {
name: "manifest"
},
splitChunks: {
cacheGroups: {
vendor: {
test: /[\/]node_modules[\/]/,
name: "vendors",
priority: -20,
chunks: "all"
}
}
}
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash:12].css',
chunkFilename: '[name].[contenthash:12].css' // use contenthash *
})
]
});
复制代码
OK,看似完美。

React、Babel、webpack都有了,接下来就是为了自己与团队之间协作代码的规范性,要通过下一个工具了。

Eslint
官网

安装
npm install eslint -g #全局安装eslint
复制代码
初始化
eslint --init
复制代码
选择默认配置
? How would you like to configure ESLint? Use a popular style guide
? Which style guide do you want to follow? Airbnb (https://github.com/airbnb/javascript)
? Do you use React? Yes
? What format do you want your config file to be in? JavaScript
Checking peerDependencies of eslint-config-airbnb@latest
? The style guide "airbnb" requires eslint@^4.19.1. You are currently using [email protected].
Do you want to downgrade? Yes
复制代码
在此直接选择airbnb。

调整配置
在初次安装后,我们发现我们之前的App.js报错了,这时我们需要调整eslint相关的配置规则,来让它更符合我们预期的使用: 打开.eslintrc.js文件,调整内容如下:

module.exports = {
"extends": "airbnb",
"plugins":[
"react",
"jsx-a11y",
"import"
],
"rules": {
"import/no-extraneous-dependencies": "off",
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"react/prop-types": 0
}
};
复制代码
更多eslint的使用姿势,还需要你个人进行探索。

引入ant-design
官网

安装
yarn add antd
复制代码
按需加载
若不想每次引用css时,可选用,在这里使用babel-plugin-import:

yarn add babel-plugin-import --dev
复制代码
修改.babelrc文件中修改为:

{
"presets": ["env", "react"],
"plugins": [
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
]
}
复制代码
试用
在App.js中,进行引用:

import { DatePicker } from 'antd';

const Home = () => (

); 复制代码 刷新后我们发现,组件是显示出来了,但是样式并没有生效。继续去找解决方案: www.jianshu.com/p/603a61471… 这位老哥写的很清楚了,原来是我们的rules配置还有点瑕疵,根据内容调整如下:

{
test: /.css$/,
exclude: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
'css-loader?modules&localIdentName=[name]-[hash:base64:5]',
],
},
{// antd样式处理
test: /.css$/,
exclude: /src/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
],
},
复制代码
调整完后,重启webpack。

关于立执行问题

export const resetPassword = (data) => () => api.user.resetPassword(data);

export const sendResetToken = (token) => api.user.sendResetToken(token);

export default {
	user: {
		login: (credentials) => axios.post('/api/auth', { credentials }).then((res) => res.data.user),
		signUp: (user) => axios.post('/api/users', { user }).then((res) => res.data.user),
		confirmToken: (token) => axios.post('/api/auth/confirmation', { token }).then((res) => res.data.user),
		resetPassword: (user) => axios.post('/api/auth/resetpassword', { user }).then((res) => res.data.user),
		sendResetToken: (token) => axios.post('/api/auth/restToken', { token }).then((res) => res.data.user)

	}
};

若api.user.sendResetToken(token)未立执行导致,如下报错:

image

处理方式

修正 :export const sendResetToken = (token) =>()=> api.user.sendResetToken(token)

项目总结

项目功能

  • 账号注册与登录,记录用户账号信息,与MondoDB进行数据交互;

  • 后端验证用户邮箱账号是否被占用,前后端验证密码,邮箱是否合法;

  • 账户邮箱验证By mailtrap, 它用于接收邮箱验证信息,该功能需在该网址下创建账号并创建收件箱,找到mailtrap的加密后username,password,以及port信息,并修改后台.env文件中的

EMAIL_PORT=2525
EMAIL_USER=e3a87a672fd2fe
EMAIL_PASS=f732fb3aee593b

用于注册与忘记密码时,获取邮箱验证链接;

  • Homepage 主页面,展示网站信息及书籍推荐,用户可在留言区域发起留言请求,合法请求将被记录于MongDB内,其它用户均可见其评论;

  • 页面展示,显示推荐书籍榜单信息,显示用户留言信息,后台读取数据库数据,传输到前端;

  • 用户添加评论,后台处理,并存入数据;

  • 用户未登录,无法发起留言请求,并自动提示需登录信息并提供导向登录页面功能;

  • 用户未登录无法通过链接地址强行访问个人书库界面,保证其安全性,(前端Redirect, 登录后设置header, 后端书库book的route需要验证请求的header);

  • 个人书库,页面自动加载,向后台发起加载收藏图书的异步请求,加载图书,实现图书的信息显示,删除以及指定地址购买的功能;

  • 添加图书收藏,根据输入信息,向后台发起搜索请求,并显示搜索结果,选取正确的数据,加载书籍信息,并添加保存至个人书库,因(接口提供信息不全,页码不包含在书籍名称中,需异步获取页码)

  • 其它功细节功能能请参考gif 或代码

关于.then 的问题处理

在 服务res 报错的情况时:

.then( ( )=> this.props.history.push('/dashboard'))
不执行push

.then(this.props.history.push("/dashboard")
会执push

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.