面对日新月异的前端,我表示快学不动了:joy:。 Webpack 老早就已经更新到了 V4.x,前段时间 React 又推出了 hooks API。刚好春节在家里休假,时间比较空闲,还是赶紧把 React 技术栈这块补上。

在安庆等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供成都网站设计、做网站 网站设计制作按需定制,公司网站建设,企业网站建设,成都品牌网站建设,成都全网营销推广,成都外贸网站建设,安庆网站建设费用合理。
网上有很多介绍 hooks 知识点的文章,但都比较零碎,基本只能写一些小 Demo 。还没有比较系统的,全新的基于 hooks 进行搭建实际项目的讲解。所以这里就从开发实际项目的角度,搭建起单页面 Web App 项目的基本脚手架,并基于 hooks API 实现一个 react 项目模版。
Hooks最吸引人的地方就是用 函数式组件 代替面向对象的 类组件 。此前的 react 如果涉及到状态,解决方案通常只能使用 类组件 ,业务逻辑一复杂就容易导致组件臃肿,模块的解藕也是个问题。而使用基于 hooks 的 函数组件 后,代码不仅更加简洁,写起来更爽,而且模块复用也方便得多,非常看好它的未来。
webpack 4 的配置
没有使用 create-react-app 这个脚手架,而是从头开始配置开发环境,因为这样自定义配置某些功能会更方便些。下面这个是通用的配置 webpack.common.js 文件。
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const { HotModuleReplacementPlugin } = require('webpack');
module.exports = {
entry: './src/index.js',//单入口
output: {
path: resolve(__dirname, 'dist'),
filename: '[name].[hash].js'//输出文件添加hash
},
optimization: { // 代替commonchunk, 代码分割
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/,
use: ['style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: true,//css modules
localIdentName: '[name]___[local]___[hash:base64:5]'
},
},
'postcss-loader', 'sass-loader']
},
{ /*
当文件体积小于 limit 时,url-loader 把文件转为 Data URI 的格式内联到引用的地方
当文件大于 limit 时,url-loader 会调用 file-loader, 把文件储存到输出目录,并把引用的文件路径改写成输出后的路径
*/
test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 1000
}
}]
}
]
},
plugins: [
new CleanWebpackPlugin(['dist']),//生成新文件时,清空生出目录
new HtmlWebpackPlugin({
template: './public/index.html',//模版路径
favicon: './public/favicon.png',
minify: { //压缩
removeAttributeQuotes:true,
removeComments: true,
collapseWhitespace: true,
removeScriptTypeAttributes:true,
removeStyleLinkTypeAttributes:true
},
}),
new HotModuleReplacementPlugin()//HMR
]
};接着基于 webpack.common.js 文件,配置出开发环境的 webpack.dev.js 文件,主要就是启动开发服务器。
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
port: 4001,
hot: true
}
});生成模式的 webpack.prod.js 文件,只要定义了 mode:'production' , webpack 4 打包时就会自动压缩优化代码。
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map'
});
配置 package.js 中的 scripts
{
"scripts": {
"start": "webpack-dev-server --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
}
}
Babel 的配置
babel的 .babelrc 文件, css module 包这里推荐 babel-plugin-react-css-modules 。
react-css-modules既支持全局的css(默认 className 属性),同时也支持局部css module( styleName 属性),还支持css预编译器,这里使用的是 scss 。
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-runtime",
[
"react-css-modules",
{
"exclude": "node_modules",
"filetypes": {
".scss": {
"syntax": "postcss-scss"
}
},
"generateScopedName": "[name]___[local]___[hash:base64:5]"
}
]
]
}React 项目
下面是项目基本的目录树结构,接着从入口开始一步步细化整个项目。
├ package.json ├ src │ ├ component // 组件目录 │ ├ reducer // reducer目录 │ ├ action.js │ ├ constants.js │ ├ context.js │ └ index.js ├ public // 静态文件目录 │ ├ css │ └ index.html ├ .babelrc ├ webpack.common.js ├ webpack.dev.js └ webpack.prod.js
状态管理组件使用 redux , react-router 用于构建单页面的项目,因为使用了 hooks API,所以不再需要 react-redux 连接状态 state 。
// index.js
import React, { useReducer } from 'react'
import { render } from 'react-dom'
import { HashRouter as Router, Route, Redirect, Switch } from 'react-router-dom'
import Context from './context.js'
import Home from './component/home.js'
import List from './component/list.js'
import rootReducer from './reducer'
import '../public/css/index.css'
const Root = () => {
const initState = {
list: [
{ id: 0, txt: 'webpack 4' },
{ id: 1, txt: 'react' },
{ id: 2, txt: 'redux' },
]
};
// useReducer映射出state,dispatch
const [state, dispatch] = useReducer(rootReducer, initState);
return
( )} />
}
render(
,
document.getElementById('root')
)
constants.js, action.js 和 reducer.js 与之前的写法是一致的。
// constants.js
export const ADD_COMMENT = 'ADD_COMMENT'
export const REMOVE_COMMENT = 'REMOVE_COMMENT'
// action.js
import { ADD_COMMENT, REMOVE_COMMENT } from './constants'
export function addComment(comment) {
return {
type: ADD_COMMENT,
comment
}
}
export function removeComment(id) {
return {
type: REMOVE_COMMENT,
id
}
}
list.js
import { ADD_COMMENT, REMOVE_COMMENT } from '../constants.js'
const list = (state = [], payload) => {
switch (payload.type) {
case ADD_COMMENT:
if (Array.isArray(payload.comment)) {
return [...state, ...payload.comment];
} else {
return [...state, payload.comment];
}
case REMOVE_COMMENT:
return state.filter(i => i.id != payload.id);
default: return state;
}
};
export default listreducer.js
import { combineReducers } from 'redux'
import list from './list.js'
const rootReducer = combineReducers({
list,
//user
});
export default rootReducer
最大区别的地方就是 component 组件,基于 函数式 ,内部的表达式就像是即插即用的插槽,可以很方便的抽取出通用的组件,然后从外部引用。相比之前的 面向对象 方式,我觉得 函数表达式 更受前端开发者欢迎。
//监控数组中的参数,一旦变化就执行
useEffect(() => { updateData(); },[id]);
//不传第二个参数的话,它就等价于每次componentDidMount和componentDidUpdate时执行
useEffect(() => { updateData(); });
//第二个参数传空数组,等价于只在componentDidMount和componentWillUnMount时执行,
//第一个参数中的返回函数用于执行清理功能
useEffect(() => {
initData();
reutrn () => console.log('componentWillUnMount cleanup...');
}, []);
最后就是实现具体界面和业务逻辑的组件了,下面是其中的List组件
// list.js
import React, { useRef, useState, useContext } from 'react'
import { bindActionCreators } from 'redux'
import { Link } from 'react-router-dom'
import Context from '../context.js'
import * as actions from '../action.js'
import Dialog from './dialog.js'
import './list.scss'
const List = () => {
const ctx = useContext(Context);//获取全局状态state
const { user, list } = ctx.state;
const [visible, setVisible] = useState(false);
const [rid, setRid] = useState('');
const inputRef = useRef(null);
const { removeComment, addComment } = bindActionCreators(actions, ctx.dispatch);
const confirmHandle = () => {
setVisible(false);
removeComment(rid);
}
const cancelHandle = () => {
setVisible(false);
}
const add = () => {
const input = inputRef.current,
val = input.value.trim();
if (!val) return;
addComment({
id: Math.round(Math.random() * 1000000),
txt: val
});
input.value = '';
}
return <>
This is list page
hello, {user.name} !
your email is {user.email} !
please add and remove the list item !!
{
list.map(l => - {l.txt} {
setVisible(true);
setRid(l.id);
}}>
)
}
redirect to home
>
}
export default List;项目代码
https://github.com/edwardzhong/webpack_react
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持创新互联。