Source address (real-time update) github.com/yayxs/Netea…
The wiki address github.com/yayxs/Netea…
preface
Project background
Based on two points :(1) the author developed react in the enterprise, but some solutions to deal with problems are still outdated. For example, redux is still written using the original switch, such as Thunk, which handles several states of network requests, including exceptions recorded before loading, and so on. There is a lot of similar code that looks awkward, but it is not easy to change the solution of enterprise projects. Therefore, I plan to develop a complete enterprise-level project to integrate the current better solution to the problem. (2) Only pay attention to the realization of the front end, plus a very perfect interface (here refers to the Api of the open source netease cloud, which must be known to everyone). So choose network suppression cloud music.
About the project
This project is a PERSONAL training project for THE JS version (currently starting from the JS version). It integrates the most practical practices in the React project and updates the progress weekly, aiming to better follow the React enterprise project development process.
React development tips. Please communicate with me. The code will be synchronized to the warehouse address at the beginning of the article (temporarily not in the code cloud).
Try to write a progress share every week. Interested guys click a star is my motivation to update.
Week 1 Results presentation
The main finished part
- The pop-up
webpack
Configure, Addsrc
The alias - configuration
.vscode
Add debugjson
configuration - finishing
Redux
Relevant practice process, run throughRedux
process Api
Of the interfaceproxy
The proxy debugaxios
The encapsulation, as wellapi
The configuration of thereact-router-dom
Initial configuration of routes
Preview
Basic introduction
The first thing to say is that the project is created using the Create React app. Then pop up the webpack configuration via NPM Run eject, removing the individual build dependencies
The directory structure
| - LICENSE | -- README. Md / / description file | - build | - config | | -- webpack. Config. Js / / webpack configuration file | - docs/post/supporting document | ` - Images | - examples | ` - proxy middleware / / nestjs project for testing interface agent | -- jsconfig. Json | -- package. Json | - public | | - The favicon. Ico | ` -- index. | - HTML scripts | - SRC | | - App. Js/App/main application | | - API/interface/API | | - assets / / resources | | - Common public configuration / / | | - components / / component | | - index. The js | | | - layouts / / layout | - pages / / page views | | - the router / / React - the router - dom routing configuration | | - services / / axios network request package | | - store/configuration/redux | | - styles / / style file | | - utils/method/tools |-- yarn.lockCopy the code
Depend on the environment
NPM script
Scripts as of the latest time
"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"
},
Copy the code
Package bag
Click the link below to jump directly to the official website for easy viewing
-
“React” : “^ 16.13.1”
-
“React-router-dom “: “^5.2.0”
-
“Story”, “^ 4.0.5”
-
“Antd” : “^ 4.6.1.” “
-
“Axios” : “^ 0.20.0”
-
“Webpack” : “4.44.1”
-
Others to be added
"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", "the react - redux" : "^ 7.2.1", "the react - the router - config" : "^ 5.1.1", "story", "^ 4.0.5", "the story - the immutable" : "^ 4.0.0", "styled - components" : "^ 5.1.1", "webpack" : "4.44.1."Copy the code
Just to be brief
antd
Use V4 big version up to now the latest, because and V3 version of the way to write there are different placesimmutable
redux-immutable
A solution for immutable redux data flow (not the best)redux
react-redux
All are the latest bags- The React version is officially up to date
Node
Such as the environment
- The node v14.8.0
Run the project
Clone project
https://github.com/yayxs/NeteaseCloudMusic.git
Copy the code
Install dependencies
NPM run check && nCU // Check the dependency package version to be updated and installedCopy the code
Project running
npm run start
Copy the code
The above commands can be replaced with yarn, etc., if you prefer
About the style of the project
Styled using the ANTD component library + Styled – Components in conjunction with Sass and 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;
}
`;
Copy the code
Write styles in the same way as above and complete the style section of the page together with SASS
Axios Network request encapsulation
/* * @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 * @ */
/ / introduce 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
// Global request interception, executed before sending the request
instance.interceptors.request.use(
function (config) {
// Do something before request is sent
// Set the request token, etc
// config.headers["authorization"] = "Bearer " + getToken();
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error); });// Add a response interceptor
// Execute after the request returns
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 request *@param {*} Url Request address *@param {*} params* /
export function get(url, params) {
return instance.get(url, {
params,
});
}
/** * Post request *@param {*} Url Request address *@param {*} data* /
export function post(url, data) {
return instance.post(url, data);
}
/** * put request *@param {*} Url Request address *@param {*} data* /
export function put(url, data) {
return instance.put(url, data);
}
/** * delete request *@param {*} url* /
export function del(url) {
return instance.delete(url);
}
Copy the code
When using, you can directly create the corresponding JS file under the @/ API folder and configure the corresponding interface
/* * @Author: yayxs * @Date: 2020-08-26 22:35:37 * @LastEditTime: 2020-08-26 23:48:17 * @LastEditors: Yayxs * @description: Recommended API * @filepath: \NeteaseCloudMusic\ SRC \ API \recommend.js * @ */
// import request from "@/services/request";
import { get } from "@/services/request";
const fetchBannerListApi = () = > get("/banner");
export { fetchBannerListApi };
Copy the code
About the interface
Please refer to the netease Cloud Music NodeJS API
Component writing
Take the header component of the header as an example
@/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">Netease Cloud Music</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; Copy the code
-
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` `; Copy the code
Redux process
There are two types of data for this project: one is the internal state of the component. Use useState hook in React hooks
const [currIndex, setCurrIndex] = useState(0);
Copy the code
Axios network requests data that we all access in Redux
Overall process
import { Provider } from "react-redux";
import store from "./store";
ReactDOM.render(
<>
<Provider store={store}>
<App />
</Provider>
</>.document.getElementById("root"));Copy the code
- 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;
Copy the code
Local component state
The local component flow is dealt with in several parts
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 * @ */
// Get the data from the rotation chart
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";
Copy the code
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) = > {});
};
Copy the code
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:
returnstate; }};Copy the code
For the reDUx process above, on the one hand you can look at this project to see the complete code, and on the other hand ** I have compiled a vertical analysis of the reDUx process practice (updated in August 2020) **
Of course you can also check directly in Juejin (if you encounter network problems) juejin.cn/post/684490…
Route lazy loading
const YYHeaderComp = lazy(() = > import("./components/header/index"));
const YYFooterComp = lazy(() = > import("./components/footer/index"));
Copy the code
Webpack alias configuration
This project adds aliases by simply modifying the webpack configuration
const resolveDir =(dir) = >{
let res = path.resolve(__dirname, dir)
console.log(res)
return res
}
Copy the code
alias: {
// Webpack configures the alias
The '@': resolveDir('.. /src'),// @ points to the SRC directory
'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 || {}), },Copy the code
The configuration of CRA
Proxy Proxy configuration
To request a proxy API in development, use http-proxy-middleware and create a new setupproxy.js file in the SRC directory. Note that the SRC directory is not the root directory of the project
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:5000'.changeOrigin: true,})); };Copy the code
The test agent
If you want to test agents, start examples/proxy-middleware (github.com/yayxs/Netea…). This is a Nest project, install dependencies, then NPM run start
other
Basic configuration of the editor
React projects can use the vscode plugin to generate code snippets quickly
At the top of the project directory there is a.vscode that is not added to the ignore file, as you can see if you use the vscode editor
-
launch.json
{ "version": "0.2.0"."configurations": [{"name": "Chrome"."type": "chrome"."request": "launch"."url": "http://localhost:3001"."webRoot": "${workspaceFolder}/src"."sourceMapPathOverrides": { "webpack:///src/*": "${webRoot}/*"}}}]Copy the code
-
settings.json
{ "emmet.includeLanguages": { "javascript": "javascriptreact"}}Copy the code
Please search for specific meanings and functions by yourself
resources
Netease Cloud official wizard picture
- S2.music.126.net/style/web2/… The head logo etc.
- S2.music.126.net/style/web2/… Downloading a Client
Related reading
- The react | react – redux | react – thunk | state | state management | state – management – compare
Q&A
Have what problem return please much exchange github.com/yayxs/Netea…
You can also add communication groups
- Front end mutual fish 1 group 713593204
This is the first netease Cloud Web version of the project to share your small praise is my motivation to update, can see here people ah, are “idle people”, old fans know our play, the comment area of the most like friends, the next post directly top [read the comments]. Give it a star, baby