React16.13.1 Net Cloud Suppression (неделя 1) | пакет axios, реализация карусели, псевдоним

React.js
React16.13.1 Net Cloud Suppression (неделя 1) | пакет axios, реализация карусели, псевдоним

Адрес источника (обновляется в режиме реального времени)GitHub.com/AsianStudent/net EA…

вики-адресGitHub.com/AsianStudent/net EA…

предисловие

история проекта

Основываясь на двух моментах: (1) Автор используетreactразработка, но некоторые решения для решения проблемы все еще относительно устарели. Например: оreduxили используйте оригиналswitchНапишите за один проход, например, используяthunkНесколько состояний для обработки сетевого запроса включаютперед загрузкой Загрузка запись исключенияПодождите, с этим надо разобраться, будет много похожего кода, который выглядит неловко, но изменить план энтерпрайз-проекта непросто. так что планРазработать полноценный проект корпоративного уровняИнтегрируйте текущее лучшее решение проблемы, (2) сосредоточьтесь только на前端реализация, плюс очень совершенная接口(имеется в виду открытый исходный код网易云Апи, это должен знать каждый). так что выбирай网抑云Музыка.

О проекте

Этот предмет является JS 版本(в настоящее время начиная с версии JS) проект персонального обучения, интегрирующий текущуюReactСамая экстремальная практика в проекте, прогресс обновляется каждую неделю, стремясь стать лучшеreactПроцесс разработки проекта на уровне предприятия.

ПоделитьсяreactМелкие точки в развитии. Надеюсь на совместное общение. Код будет синхронизирован с адресом склада в начале статьи (пока не размещен в облаке кодов).

Старайтесь писать одну статью в неделю进度分享. Заинтересованные ребята могут нажатьstarЭто моя мотивация для обновления.

Итоги первой недели

основная завершенная часть

  • неожиданно возникнутьwebpackнастроить, добавитьsrcпсевдоним
  • настроить.vscodeдобавить отладкуjsonнастроить
  • аккуратныйReduxСоответствующий практический процесс, прохождениеReduxПроцесс
  • ApiинтерфейсproxyОтладка прокси
  • axiosпакет иapiКонфигурация
  • react-router-domНачальная настройка маршрутизации

Preview

основное введение

Первое, что нужно сказать, это то, чтоэлемент используетcreate react app создавать . затем пройтиnpm run ejectнеожиданно возникнутьwebpackconfig для удаления отдельных зависимостей сборки

Структура каталогов

|-- LICENSE
|-- README.md					// 描述文件
|-- build
|-- config
|   |-- webpack.config.js		// webpack 配置文件
|-- docs 						// 配套文档博文
|   `-- images
|-- examples
|   `-- proxy-middleware		// nestjs 项目  用于测试接口代理
|-- jsconfig.json
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- scripts
|-- src
|   |-- App.js					// App 主应用
|   |-- api						// api 接口
|   |-- assets					// 资源
|   |-- common					// 公用配置
|   |-- components				// 组件
|   |-- index.js		
|   |-- layouts					// 布局
|   |-- pages					// 页面 views
|   |-- router					// react-router-dom 路由配置
|   |-- services				// axios 网络请求封装
|   |-- store					// redux 配置
|   |-- styles					// 样式文件
|   |-- utils					// 工具方法				
|-- yarn.lock

зависимая среда

нпм-скрипт

Последнее времяscriptsсценарий

 "scripts": {
    "analyze": "source-map-explorer 'build/static/js/*.js'",
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "node scripts/test.js",
    "clear": "rimraf node_modules &&  yarn add",
    "check": "npm install -g && npm-check-updates",
    "ncu": "ncu -u && npm i"
  },

упаковка

Нажмите на ссылку ниже, чтобы перейти непосредственно на официальный сайт для удобного просмотра


"antd": "^4.6.1",
"axios": "^0.20.0",
"classnames": "^2.2.6",
"http-proxy-middleware": "^1.0.5",
"husky": "^4.2.5",
"immutable": "^4.0.0-rc.12",
"normalize.css": "^8.0.1",
"react-redux": "^7.2.1",
"react-router-config": "^5.1.1",
"redux": "^4.0.5",
"redux-immutable": "^4.0.0",
"styled-components": "^5.1.1",
"webpack": "4.44.1",

просто скажи

  • antdВерсия V4 является последней версией, поскольку она отличается от версии V3.
  • immutable redux-immutableНеизменяемое решение для избыточного потока данных (не самое лучшее)
  • redux react-reduxВсе последние пакеты
  • reactВерсия является последней официальной версией

Nodeдругая среда

  • node v14.8.0

запустить проект

клонировать проект

https://github.com/yayxs/NeteaseCloudMusic.git

Установить зависимости

npm run check && ncu // 检查依赖包版本  更新至最新并安装

Запуск проекта

npm run start

Выше命令также можно заменить наyarnподожди, если хочешь

О стиле проекта

использоватьantdБиблиотека компонентов +styled-componentsкомбинироватьsassа такжеnormalize.cssсбросить стиль

import styled from "styled-components";

export const WrapperContainer = styled.div`
  height: 285px;
  width: 100vw;
  background: url(${(props) => props.bgImage}) center center/6000px;

  .banner {
    height: 285px;
    display: flex;
    position: relative;
  }
`;

Напишите стиль указанным выше способом в сочетании сsassСовместная работа над оформлением части страницы

инкапсуляция сетевых запросов axios

/*
 * @Author: yayxs
 * @Date: 2020-08-26 21:37:00
 * @LastEditTime: 2020-08-26 23:54:10
 * @LastEditors: yayxs
 * @Description:
 * @FilePath: \NeteaseCloudMusic\src\services\request.js
 * @
 */
// 引入axios
import axios from "axios";
// import * as commonConfig from "../common/config";

const instance = axios.create({
  baseURL: process.env.REACT_APP_BASE_URL,
  timeout: Number(process.env.REACT_APP_TIME_OUT),
});

// Add a request interceptor
//  全局请求拦截,发送请求之前执行
instance.interceptors.request.use(
  function (config) {
    // Do something before request is sent
    // 设置请求的 token 等等
    // config.headers["authorization"] = "Bearer " + getToken();
    return config;
  },
  function (error) {
    // Do something with request error
    return Promise.reject(error);
  }
);

// Add a response interceptor
//  请求返回之后执行
instance.interceptors.response.use(
  function (response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data
    return response.data;
  },
  function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error);
  }
);

/**
 * get请求
 * @param {*} url     请求地址
 * @param {*} params
 */
export function get(url, params) {
  return instance.get(url, {
    params,
  });
}

/**
 * post请求
 * @param {*} url     请求地址
 * @param {*} data
 */
export function post(url, data) {
  return instance.post(url, data);
}

/**
 * put请求
 * @param {*} url     请求地址
 * @param {*} data
 */
export function put(url, data) {
  return instance.put(url, data);
}

/**
 * delete请求
 * @param {*} url
 */
export function del(url) {
  return instance.delete(url);
}


При использовании вы можете напрямую@/apiСоздайте соответствующую папкуjsфайл, а затем настроить соответствующий интерфейс

/*
 * @Author: yayxs
 * @Date: 2020-08-26 22:35:37
 * @LastEditTime: 2020-08-26 23:48:17
 * @LastEditors: yayxs
 * @Description: 推荐 API
 * @FilePath: \NeteaseCloudMusic\src\api\recommend.js
 * @
 */
// import request from "@/services/request";

import { get } from "@/services/request";

const fetchBannerListApi = () => get("/banner");

export { fetchBannerListApi };

Об интерфейсе

Пожалуйста, обратитесь кAPI NetEase Cloud Music NodeJS

обозначение компонента

с головойheader组件为例子

@/components/header

  • index.jsx

    import React, { memo } from "react";
    import classnames from "classnames";
    import { WarpperContainer, StyledLeft, StyledRight } from "./styled";
    import { NavLink } from "react-router-dom";
    import { headerNavConfig } from "../../common/config";
    const HeaderComp = memo(() => {
      return (
        <WarpperContainer>
          <div className="wrap_1100_center container">
            <StyledLeft>
              <a hidefocus="true" href="/#" className="logo sprite_topbar">
                网易云音乐
              </a>
              <ul>
                {headerNavConfig.map((item) => (
                  <li key={item.title} className={classnames("setected_nav")}>
                    <NavLink to={item.path}>
                      {item.title}
                      <i className="sprite_topbar icon"></i>
                    </NavLink>
                  </li>
                ))}
              </ul>
            </StyledLeft>
            <StyledRight></StyledRight>
          </div>
        </WarpperContainer>
      );
    });
    
    export default HeaderComp;
    
    
  • styled.js

    /*
     * @Author: yayxs
     * @Date: 2020-08-24 23:28:16
     * @LastEditTime: 2020-08-25 23:28:36
     * @LastEditors: yayxs
     * @Description:
     * @FilePath: \NeteaseCloudMusic\src\components\header\styled.js
     * @
     */
    import styled from "styled-components";
    
    export const WarpperContainer = styled.div`
      width: 100vw;
      height: 70px;
      background-color: #242424;
      .container {
        display: flex;
      }
    `;
    
    export const StyledLeft = styled.div`
      display: flex;
      .logo {
        display: block;
        width: 176px;
        height: 69px;
        background-position: 0 0;
        text-indent: -9999px;
      }
      ul {
        width: 508px;
        height: 70px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        li {
          font-size: 14px;
          color: #ccc;
        }
      }
    `;
    export const StyledRight = styled.div``;
    
    

редукционный процесс

Данные для этого проекта разделены на двеОдин из них — это состояние внутри компонента. В это время мы используемreact hooksсерединаuseState hookрешать

const [currIndex, setCurrIndex] = useState(0);

axiosМы всегда получаем доступ к данным, запрошенным сетью вredux

общий процесс

import { Provider } from "react-redux";
import store from "./store";

ReactDOM.render(
  <>
    <Provider store={store}>
      <App />
    </Provider>
  </>,
  document.getElementById("root")
);
  • store/index.js
/*
 * @Author: yayxs
 * @Date: 2020-08-22 11:48:40
 * @LastEditTime: 2020-08-26 23:01:17
 * @LastEditors: yayxs
 * @Description:
 * @FilePath: \NeteaseCloudMusic\src\store\index.js
 * @
 */
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";
const middlewares = [thunk];
if (process.env.NODE_ENV === `development`) {
  const { logger } = require(`redux-logger`);

  middlewares.push(logger);
}

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  reducer,
  /* preloadedState, */ composeEnhancers(applyMiddleware(...middlewares))
);

export default store;

состояние локального компонента

Что касается процесса локальной составляющей, то мы разделим его на несколько частей

actionTypes.js

/*
 * @Author: yayxs
 * @Date: 2020-08-26 22:27:29
 * @LastEditTime: 2020-08-26 22:32:33
 * @LastEditors: yayxs
 * @Description:
 * @FilePath: \NeteaseCloudMusic\src\pages\foundMusic\childrenPages\recommend\store\actionTypes.js
 * @
 */
// 获取轮播图数据
export const FETCH_BANNER_LIST_SUCCESS = "FETCH_BANNER_LIST_SUCCESS";
export const FETCH_BANNERLIST_BEGIN = "FETCH_BANNERLIST_BEGIN";
export const FETCH_BANNERLIST_ERROR = "FETCH_BANNERLIST_ERROR";

actionCreators

/*
 * @Author: yayxs
 * @Date: 2020-08-26 22:27:33
 * @LastEditTime: 2020-08-27 21:07:49
 * @LastEditors: yayxs
 * @Description:
 * @FilePath: \NeteaseCloudMusic\src\pages\foundMusic\childrenPages\recommend\store\actionCreators.js
 * @
 */
import { fetchBannerListApi } from "@/api/recommend.js";
import { FETCH_BANNER_LIST_SUCCESS } from "./actionTypes";

export const changeBannerLsitAction = (data) => ({
  type: FETCH_BANNER_LIST_SUCCESS,
  payload: { data },
});

export const getBannerListAsyncAction = () => (dispatch) => {
  fetchBannerListApi()
    .then((res) => {
      if (res.code === 200) {
        dispatch(changeBannerLsitAction(res.banners));
      }
    })
    .catch((err) => {});
};

reducer

/*
 * @Author: yayxs
 * @Date: 2020-08-26 22:27:34
 * @LastEditTime: 2020-08-27 21:09:44
 * @LastEditors: yayxs
 * @Description:
 * @FilePath: \NeteaseCloudMusic\src\pages\foundMusic\childrenPages\recommend\store\reducer.js
 * @
 */
import { Map } from "immutable";
import * as actionTypes from "./actionTypes";

const initState = Map({
  bannersList: [],
});

export default (state = initState, action) => {
  switch (action.type) {
    case actionTypes.FETCH_BANNER_LIST_SUCCESS:
      return state.set("bannersList", action.payload.data);

    default:
      return state;
  }
};

о вышеизложенномreduxС одной стороны, вы можете обратить внимание на этот проект для просмотра полного кода, с другой стороны**Я составил практику лонгитюдного анализа редукс-процесса (обновлено в августе 2020 г.)**

Конечно, вы также можете напрямуюjuejin 查看(если у вас возникли проблемы с сетью)nuggets.capable/post/684490…

Отложенная загрузка маршрута

const YYHeaderComp = lazy(() => import("./components/header/index"));
const YYFooterComp = lazy(() => import("./components/footer/index"));

конфигурация псевдонима webpack

Этот проект путем простой модификацииwebpackконфиг для добавления алиасов (псевдонимов)

const resolveDir =(dir)=>{
  let res  = path.resolve(__dirname, dir)
  console.log(res)
  return res
}
   alias: {
        // webpack 配置别名
        '@': resolveDir('../src') ,// 这样配置后 @ 可以指向 src 目录
        'components': resolveDir("../src/components"),
        // Support React Native Web
        // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
        'react-native': 'react-native-web',
        // Allows for better profiling with ReactDevTools
        ...(isEnvProductionProfile && {
          'react-dom$': 'react-dom/profiling',
          'scheduler/tracing': 'scheduler/tracing-profiling',
        }),
        ...(modules.webpackAliases || {}),
      },

Конфигурация CRA

прокси конфигурация прокси

агент в разработкеAPIзапрос, черезhttp-proxy-middlewareзатем вsrcновый каталогsetupProxy.jsдокумент. Обратите внимание, чтоsrcКаталог не является корневым каталогом проекта

const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:5000',
      changeOrigin: true,
    })
  );
};

тестовый агент

Если вы хотите протестировать прокси, вы можете начатьexamples/proxy-middleware (GitHub.com/AsianStudent/net EA…) это вложенный проект, устанавливаем зависимости, затемnpm run start

разное

Базовая конфигурация редактора

ПисатьReactПредметы могут использоватьvscodeПлагин, быстро генерирующий фрагменты кода

В самом верху каталога проекта есть.vscodeи не добавляется для игнорирования файлов, если вы используетеvscodeРедактор, ты увидишь

  • launch.json

    {
      "version": "0.2.0",
      "configurations": [
        {
          "name": "Chrome",
          "type": "chrome",
          "request": "launch",
          "url": "http://localhost:3001",
          "webRoot": "${workspaceFolder}/src",
          "sourceMapPathOverrides": {
            "webpack:///src/*": "${webRoot}/*"
          }
        }
      ]
    }
    
    
  • settings.json

    {
      "emmet.includeLanguages": {
        "javascript": "javascriptreact"
      }
    }
    
    

Пожалуйста, обратитесь к конкретному значению и функции搜索

ресурс

Официальная карта спрайтов облака Netease

Связанное чтение

Q&A

Если у вас есть какие-либо вопросы, пожалуйста, свяжитесь с нами большеGitHub.com/AsianStudent/net EA…

Вы также можете добавить группы чата

  • Фронтальная взаимная рыбка 1 группа 713593204

Это网易云web版本项目的第一篇分享Ваши маленькие лайки - это мотивация для меня, чтобы обновить. Люди, которые могут видеть здесь, все "бездельники". Старые фанаты знают, как мы играем. Друг с наибольшим количеством лайков в области комментариев напрямую закрепит следующую статью наверху [прочитать комментарий]. датьstarбар дорогой