欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Webpack4和React hooks搭建項(xiàng)目的方法

 更新時(shí)間:2019年02月05日 09:29:24   作者:Jeff.Zhong  
這篇文章主要介紹了基于Webpack4和React hooks搭建項(xiàng)目的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

面對(duì)日新月異的前端,我表示快學(xué)不動(dòng)了:joy:。 Webpack 老早就已經(jīng)更新到了 V4.x,前段時(shí)間 React 又推出了 hooks API。剛好春節(jié)在家里休假,時(shí)間比較空閑,還是趕緊把 React 技術(shù)棧這塊補(bǔ)上。

網(wǎng)上有很多介紹 hooks 知識(shí)點(diǎn)的文章,但都比較零碎,基本只能寫(xiě)一些小 Demo 。還沒(méi)有比較系統(tǒng)的,全新的基于 hooks 進(jìn)行搭建實(shí)際項(xiàng)目的講解。所以這里就從開(kāi)發(fā)實(shí)際項(xiàng)目的角度,搭建起單頁(yè)面 Web App 項(xiàng)目的基本腳手架,并基于 hooks API 實(shí)現(xiàn)一個(gè) react 項(xiàng)目模版。

Hooks最吸引人的地方就是用 函數(shù)式組件 代替面向?qū)ο蟮?類(lèi)組件 。此前的 react 如果涉及到狀態(tài),解決方案通常只能使用 類(lèi)組件 ,業(yè)務(wù)邏輯一復(fù)雜就容易導(dǎo)致組件臃腫,模塊的解藕也是個(gè)問(wèn)題。而使用基于 hooks 的 函數(shù)組件 后,代碼不僅更加簡(jiǎn)潔,寫(xiě)起來(lái)更爽,而且模塊復(fù)用也方便得多,非??春盟奈磥?lái)。

webpack 4 的配置

沒(méi)有使用 create-react-app 這個(gè)腳手架,而是從頭開(kāi)始配置開(kāi)發(fā)環(huán)境,因?yàn)檫@樣自定義配置某些功能會(huì)更方便些。下面這個(gè)是通用的配置 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']
      },
      {  /* 
        當(dāng)文件體積小于 limit 時(shí),url-loader 把文件轉(zhuǎn)為 Data URI 的格式內(nèi)聯(lián)到引用的地方
        當(dāng)文件大于 limit 時(shí),url-loader 會(huì)調(diào)用 file-loader, 把文件儲(chǔ)存到輸出目錄,并把引用的文件路徑改寫(xiě)成輸出后的路徑 
        */
        test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 1000
          }
        }]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(['dist']),//生成新文件時(shí),清空生出目錄
    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 文件,配置出開(kāi)發(fā)環(huán)境的 webpack.dev.js 文件,主要就是啟動(dòng)開(kāi)發(fā)服務(wù)器。

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 打包時(shí)就會(huì)自動(dòng)壓縮優(yōu)化代碼。

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(默認(rèn) className 屬性),同時(shí)也支持局部css module( styleName 屬性),還支持css預(yù)編譯器,這里使用的是 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 項(xiàng)目

下面是項(xiàng)目基本的目錄樹(shù)結(jié)構(gòu),接著從入口開(kāi)始一步步細(xì)化整個(gè)項(xiàng)目。

├ package.json
├ src
│ ├ component // 組件目錄
│ ├ reducer  // reducer目錄
│ ├ action.js
│ ├ constants.js
│ ├ context.js
│ └ index.js
├ public // 靜態(tài)文件目錄
│ ├ css
│ └ index.html
├ .babelrc
├ webpack.common.js
├ webpack.dev.js
└ webpack.prod.js

狀態(tài)管理組件使用 redux , react-router 用于構(gòu)建單頁(yè)面的項(xiàng)目,因?yàn)槭褂昧?hooks API,所以不再需要 react-redux 連接狀態(tài) state 。

<Context.Provider value={{ state, dispatch }}>基本代替了 react-redux 的 ** `。

// 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 <Context.Provider value={{ state, dispatch }}>
    <Router>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route exact path="/list" component={List} />
        <Route render={() => (<Redirect to="/" />)} />
      </Switch>
    </Router>
  </Context.Provider>
}
render(
  <Root />,
  document.getElementById('root')
)

constants.js, action.js 和 reducer.js 與之前的寫(xiě)法是一致的。

// 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 list

reducer.js

import { combineReducers } from 'redux'
import list from './list.js'

const rootReducer = combineReducers({
 list,
 //user
});

export default rootReducer

最大區(qū)別的地方就是 component 組件,基于 函數(shù)式 ,內(nèi)部的表達(dá)式就像是即插即用的插槽,可以很方便的抽取出通用的組件,然后從外部引用。相比之前的 面向?qū)ο?方式,我覺(jué)得 函數(shù)表達(dá)式 更受前端開(kāi)發(fā)者歡迎。

  • useContext 獲取全局的 state
  • useRef 代替之前的 ref
  • useState 代替之前的 state
  • useEffect則可以代替之前的生命周期鉤子函數(shù)
//監(jiān)控?cái)?shù)組中的參數(shù),一旦變化就執(zhí)行
useEffect(() => { updateData(); },[id]);

//不傳第二個(gè)參數(shù)的話,它就等價(jià)于每次componentDidMount和componentDidUpdate時(shí)執(zhí)行
useEffect(() => { updateData(); });

//第二個(gè)參數(shù)傳空數(shù)組,等價(jià)于只在componentDidMount和componentWillUnMount時(shí)執(zhí)行, 
//第一個(gè)參數(shù)中的返回函數(shù)用于執(zhí)行清理功能
useEffect(() => { 
  initData(); 
  reutrn () => console.log('componentWillUnMount cleanup...'); 
}, []);

最后就是實(shí)現(xiàn)具體界面和業(yè)務(wù)邏輯的組件了,下面是其中的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);//獲取全局狀態(tài)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 <>
    <div styleName="form">
      <h3 styleName="sub-title">This is list page</h3>
      <div>
        <p>hello, {user.name} !</p>
        <p>your email is {user.email} !</p>
        <p styleName="tip">please add and remove the list item !!</p>
      </div>
      <ul> {
        list.map(l => <li key={l.id}>{l.txt}<i className="icon-minus" title="remove item" onClick={() => {
          setVisible(true);
          setRid(l.id);
        }}></i></li>)
      } </ul>
      <input ref={inputRef} type="text" />
      <button onClick={add} title="add item">Add Item</button>
      <Link styleName="link" to="/">redirect to home</Link>
    </div>
    <Dialog visible={visible} confirm={confirmHandle} cancel={cancelHandle}>remove this item ?</Dialog>
  </>
}

export default List;

項(xiàng)目代碼

https://github.com/edwardzhong/webpack_react

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解基于webpack搭建react運(yùn)行環(huán)境

    詳解基于webpack搭建react運(yùn)行環(huán)境

    本篇文章主要介紹了詳解基于webpack搭建react運(yùn)行環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • 詳解React+Koa實(shí)現(xiàn)服務(wù)端渲染(SSR)

    詳解React+Koa實(shí)現(xiàn)服務(wù)端渲染(SSR)

    這篇文章主要介紹了詳解React+Koa實(shí)現(xiàn)服務(wù)端渲染(SSR),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • React組件學(xué)習(xí)之Hooks使用

    React組件學(xué)習(xí)之Hooks使用

    這篇文章主要介紹了React hooks組件通信,在開(kāi)發(fā)中組件通信是React中的一個(gè)重要的知識(shí)點(diǎn),本文通過(guò)實(shí)例代碼給大家講解react hooks中常用的父子、跨組件通信的方法,需要的朋友可以參考下
    2022-08-08
  • react組件memo useMemo useCallback使用區(qū)別示例

    react組件memo useMemo useCallback使用區(qū)別示例

    這篇文章主要為大家介紹了react組件memo useMemo useCallback使用區(qū)別的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • React和Vue組件更新的實(shí)現(xiàn)及區(qū)別

    React和Vue組件更新的實(shí)現(xiàn)及區(qū)別

    React 和 Vue 都是當(dāng)今最流行的前端框架,它們都實(shí)現(xiàn)了組件化開(kāi)發(fā)模式,本文將從React和Vue的組件更新原理入手,剖析兩者虛擬DOM difer算法的異同點(diǎn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • React?Hooks項(xiàng)目實(shí)戰(zhàn)

    React?Hooks項(xiàng)目實(shí)戰(zhàn)

    React?Hooks是React?16.8版本引入的新特性,它使得在函數(shù)組件中也能夠使用狀態(tài)(state)和其他React特性,本文就來(lái)詳細(xì)介紹一下React?Hooks項(xiàng)目實(shí)戰(zhàn),感興趣的可以了解一下
    2023-11-11
  • React中DOM事件和狀態(tài)介紹

    React中DOM事件和狀態(tài)介紹

    這篇文章主要介紹了React中DOM事件和狀態(tài)介紹,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-08-08
  • react中form.setFieldvalue數(shù)據(jù)回填時(shí) value和text不對(duì)應(yīng)的問(wèn)題及解決方法

    react中form.setFieldvalue數(shù)據(jù)回填時(shí) value和text不對(duì)應(yīng)的問(wèn)題及解決方法

    這篇文章主要介紹了react中form.setFieldvalue數(shù)據(jù)回填時(shí) value和text不對(duì)應(yīng)的問(wèn)題及解決方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • React State與生命周期詳細(xì)介紹

    React State與生命周期詳細(xì)介紹

    React將組件(component)看成一個(gè)狀態(tài)機(jī)(State Machines),通過(guò)其內(nèi)部自定義的狀態(tài)(State)和生命周期(Lifecycle)實(shí)現(xiàn)并與用戶(hù)交互,維持組件的不同狀態(tài)
    2022-08-08
  • React各種狀態(tài)管理器的解讀及使用方法

    React各種狀態(tài)管理器的解讀及使用方法

    這篇文章主要介紹了對(duì)于React各種狀態(tài)管理器的解讀,文中給大家提到了狀態(tài)管理器是如何使用的,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12

最新評(píng)論