react学习笔记

使用webpack打包react多页应用

demo地址: https://github.com/zhuweileo/koa-login

1. 依赖清单

  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "@babel/preset-react": "^7.0.0",
    "autoprefixer": "^9.4.7",
    "babel-loader": "^8.0.5",
    "cross-env": "^5.2.0",
    "css-loader": "^2.1.0",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.5.0",
    "node-sass": "^4.11.0",
    "postcss-loader": "^3.0.0",
    "react-hot-loader": "^4.6.4",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.31.0",
    "webpack-cli": "^3.3.2",
    "webpack-dev-server": "^3.4.1"
  },

2. webpack配置文件(部署)

webpack.config.js

var path = require('path');
var htmlPlugin = require('html-webpack-plugin');
var MiniCssExtractPlugin = require("mini-css-extract-plugin");
var {pages} = require('./page-map'); 

module.exports = {
  entry: getEntry(pages),
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name]/[name].js', // 保证每个页面可以打包进不同文件夹
  },
  mode: 'production',
  externals:{
    react: 'React', //不将react打包进来
    'react-dom': 'ReactDOM'
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use:{
          loader: "babel-loader",
        }
      },
      {
        test: /\.css$/,
        // exclude: /node_modules/, //不能加这个,否则import 'antd/dist/antd.css' 时会报错
        use: [
          process.env.NODE_ENV === 'production'? MiniCssExtractPlugin.loader: 'style-loader',
          "css-loader",
        ]
      },
      {
        test: /\.scss$/,
        use: [
          // fallback to style-loader in development
          process.env.NODE_ENV === 'production'? MiniCssExtractPlugin.loader: 'style-loader',
          "css-loader",
          "sass-loader",
        ]
      },
    ]
  },
  plugins: getPlugins(pages),
}

function getEntry(pages) {
  var entry = {}
  pages.forEach(function (item) {
    entry[item.name] = item.entry;
  })
  return entry
}

function getPlugins(pages) {
  var plugins = [
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: "[name]/[name].css", //保证每个页面的css可以放在自己的文件夹内
      chunkFilename: "[name]/[id].css"
    })
  ]

  pages.forEach(function (item) {
    var plugin =new htmlPlugin({
      filename: `${item.name}/${item.name}.html`,  //保证每个页面的html可以放在自己的文件夹内
      template: path.resolve(__dirname,item.template),
      chunks: [item.name], //html只引入自己的js和css
    })
    plugins.push(plugin);
  })
  return plugins
}

page-map.js

var path = require('path');

var pages = [
  {
    name: 'home',
    entry: path.resolve(__dirname, '../src/entry/home.js'),
    template: path.resolve(__dirname, '../src/templates/home.html'),
  },
  {
    name: 'login',
    entry: path.resolve(__dirname, '../src/entry/login.js'),
    template: path.resolve(__dirname, '../src/templates/login.html'),
  },
]


module.exports = {
  pages,
}

.babelrc

{
  "presets": ["@babel/preset-env","@babel/preset-react"]
}

如何使用react hook 获取数据

该总结翻译自以下文章的部分内容(根据自己理解做了修改,文章有点长没翻译完):

https://www.robinwieruch.de/react-hooks-fetch-data/

使用hook获取数据

这里使用axios获取数据,第一版代码如下:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [data, setData] = useState({ hits: [] });

  useEffect(async () => {
    const result = await axios(
      'http://hn.algolia.com/api/v1/search?query=redux',
    );

    setData(result.data);
  });

  return (
    
  );
}

export default App;

上面代码的问题在于:useEffect会在组件装载和更新的时候执行,然后我们又会在useEffect的回掉中去更新组件,就会引起一个死循环。我们实际上只想在组件装载的时候获取数据。

第二版修改如下:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [data, setData] = useState({ hits: [] });

  useEffect(async () => {
    const result = await axios(
      'http://hn.algolia.com/api/v1/search?query=redux',
    );

    setData(result.data);
  }, []);  //修改在这里

  return (
    
  );
}

export default App;

useEffect的第二个参数,可以effect所依赖的变量,依赖发生变化,effect回掉才会执行。如果第二个参数为空数组,代表effect不应依赖任何变量,因此,effect回掉只在组件装载时执行。

上面代码仍然是有问题的,我们把一个async函数作为useEffect函数的回掉,async函数默认返回一个promise对象,但是useEffect的回掉函数应该不返回内容,或者返回一个纯函数,控制台中会有如下警告Warning: useEffect function must return a cleanup function or nothing. Promises and useEffect(async () => …) are not supported, but you can call an async function inside an effect.

我们进行第三版代码调整:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [data, setData] = useState({ hits: [] });

  useEffect(() => {
    const fetchData = async () => {
      const result = await axios(
        'http://hn.algolia.com/api/v1/search?query=redux',
      );

      setData(result.data);
    };

    fetchData();
  }, []);

  return (
    
  );
}

export default App;

如何使用程序触发一个hook式的数据获取

以上我们讲了如何在组件装载时通过hook获取数据,下面举例如何通过input出发数据的获取。

function App() {
  const [data, setData] = useState({ hits: [] });
  const [query, setQuery] = useState('redux');
  const [search, setSearch] = useState('redux');

  useEffect(() => {
    const fetchData = async () => {
      const result = await axios(
        `http://hn.algolia.com/api/v1/search?query=${search}`,
      );

      setData(result.data);
    };

    fetchData();
  }, [search]);

  return (
    
       setQuery(event.target.value)}
      />
      

      
    
  );
}

上面的例子中,useEffect的二个参数中多了一个search变量,因此useEffect不仅会在装载组件时执行,也会在search变化时执行,注意search是一个state hook。根据代码,search的值会在点击按钮时,取query的值,query的值会在input的值改变时改变。因此流程就是:

  1. input值改变query值改变
  2. 点击按钮,取此时的query值去作为search的值
  3. search的值改变触发useEffect hook去请求接口获取数据。

使用hook显示加载中

import React, { Fragment, useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [data, setData] = useState({ hits: [] });
  const [query, setQuery] = useState('redux');
  const [url, setUrl] = useState(
    'http://hn.algolia.com/api/v1/search?query=redux',
  );
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setIsLoading(true);

      const result = await axios(url);

      setData(result.data);
      setIsLoading(false);
    };

    fetchData();
  }, [url]);

  return (
    
       setQuery(event.target.value)}
      />
      

      {isLoading ? (
        
Loading ...
) : ( )}
); } export default App;

原理很简单:当数据开始加载时isLoading状态赋值为true,加载完成时赋值为false

使用hook进行错误处理

import React, { Fragment, useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [data, setData] = useState({ hits: [] });
  const [query, setQuery] = useState('redux');
  const [url, setUrl] = useState(
    'http://hn.algolia.com/api/v1/search?query=redux',
  );
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setIsError(false);
      setIsLoading(true);

      try {
        const result = await axios(url);

        setData(result.data);
      } catch (error) {
        setIsError(true);
      }

      setIsLoading(false);
    };

    fetchData();
  }, [url]);

  return (
    
       setQuery(event.target.value)}
      />
      

      {isError && 
Something went wrong ...
} {isLoading ? (
Loading ...
) : ( )}
); } export default App;

道理和loading是一样的,使用try catch捕获错误,改变isError状态。

你可能感兴趣的:(react学习笔记)