Hello everyone, I am God three yuan.
Last time out of the server render the article, got a lot of big guy praise comments, very happy. After a period of time some people asked me why I suddenly disappeared in the nuggets, in fact is not, this community is often in the attention, but, more importantly, this paragraph of time out of your field of vision, I decided to start settling some technical things, learn some of the techniques before the stack and some thinking to do a checking of front-end engineering and integration, as a result, I started with an idea I had a long time ago, to make a music webApp. There have been a number of webApps like this, but in fact most versions of Vue, even react projects, have stopped maintenance, hooks haven’t been updated, and the whole development approach is not what I like. However, please rest assured that starting such an open source project is not the existing project to set a template, I will be long-term maintenance, and if you can read this article or read the source code you will see a completely different development ideas and development methods, learn a lot of hard work.
Ok, now to introduce the project formally.
Online Experience Address
(At present, there are some style problems in opening gold nuggets. Please open it with your browser first. Thank you for understanding.)
Chrome on mobile and PC is better:)
The source code is attached at the end.
I. Introduction to technology stack
Front end:
The react v16.8
React (React – Router) : MVVM framework for building user interfacesredux
: famous JavaScript state management containerredux-thunk
: Redux middleware that handles asynchronous logicimmutable
The memo wrapped function component works like a PureComponent, performing a shallow comparison of data before the component is updated. See this articleWhen PureComponent meets ImmutableJS)react-lazyload
React Lazy library loadingbetter-scroll
: a well-known library to enhance the mobile sliding experiencestyled-components
: Handling styles that represent front-end engineering artifacts of CSS in JS (see my previous article for details)Styled – Components: New idea for front-end component separation)axios
: The data used to request the backend API
Back-end part:
- NeteaseCloudMusicApi, the well-known API of netease CloudMusic NodeJS version on Github, is used to provide music data.
Other:
- Create-react -app: React scaffolding, quick build projects
- Eslint: Well-known code style checker
- Iconfont: Alibaba icon library
- Fastclick: Solve the problem of 300ms click delay on mobile
Ii. Project specifications
Before introducing the features of the project, I need to highlight one of the development specifications of the project and my own coding style. In advance, I do this for my own good reasons, to make the project as readable and maintainable as possible. I hope that I will not be surprised to see some strange operations later.
1, class components are no longer used; fully embrace hooks, use function components.
Internal component state is handled by hooks. All business data is managed in REdux.
3. Ajax request and subsequent data processing specific code is all in actionCreator, processed by Redux-Thunk, as much as possible to simplify the component code.
4. Each container component has its own reducer, which is merged under the global store by Redux combineReducer method.
5. JS variable names (including function names) are styled as small humps, and styled container names derived from component names or styled- Components are styled as large humps, and constant names are capitalized.
6, ordinary CSS class names are all in English lowercase, words are connected with the underscore, CSS animation hook class name words are connected with -.
If there is any data in the props, the components should be decomposed in advance, and the properties and methods should be declared separately. Also, the props obtained from the parent component and the props derived from the react-redux mapping should be declared separately.
UseEffect is written uniformly at the front and immediately after the props destruct assignment code.
All functions responsible for returning JSX should be clustered at the end of the function, without interspersing event handlers and other logic.
MapDispatchToProps returns a function name in xxxDispatch format to avoid conflicts with existing action names.
Iii. Overall project structure and demonstration
Note: This project refers to the interface development of netease Cloud Music Android app. The basic wheel component does not use any UI framework, which is a challenge to myself. I have learned a lot of design experience in this process.
Since it is difficult to upload videos, but the pictures are monotonous, which cannot reflect the dynamic of the webApp, GIF is used below.
1. Recommendation
Home recommendation:
2. Singers
List of singers:
Singer details:
3. Leaderboards
List page:
4. Player
Player kernel:
Playlist:
It will have the same rebound effect as mobile app.
5. Search
4. Share some modules of the project
1, use better Scroll to create super easy to use scroll basic components
import React, { forwardRef, useState,useEffect, useRef, useImperativeHandle } from "react"
import PropTypes from "prop-types"
import BScroll from "better-scroll"
import styled from 'styled-components';
import { debounce } from ".. /.. /api/utils";
const ScrollContainer = styled.div` width: 100%; height: 100%; overflow: hidden; `
const Scroll = forwardRef((props, ref) = > {
const [bScroll, setBScroll] = useState();
const scrollContaninerRef = useRef();
const { direction, click, refresh, pullUpLoading, pullDownLoading, bounceTop, bounceBottom } = props;
const { pullUp, pullDown, onScroll } = props;
useEffect((a)= > {
const scroll = new BScroll(scrollContaninerRef.current, {
scrollX: direction === "horizental".scrollY: direction === "vertical".probeType: 3.click: click,
bounce: {top: bounceTop,
bottom: bounceBottom
}
});
setBScroll(scroll);
if(pullUp) {
scroll.on('scrollEnd', () = > {// Check if it slides to the bottom
if(scroll.y <= scroll.maxScrollY + 100){ pullUp(); }}); }if(pullDown) {
scroll.on('touchEnd', (pos) => {
// Determine the user's pull
if(pos.y > 50) {
debounce(pullDown, 0)();
}
});
}
if(onScroll) {
scroll.on('scroll', (scroll) => { onScroll(scroll); })}if(refresh) {
scroll.refresh();
}
return (a)= > {
scroll.off('scroll');
setBScroll(null);
}
// eslint-disable-next-line} []); useEffect((a)= > {
if(refresh && bScroll){
bScroll.refresh();
}
})
useImperativeHandle(ref, () => ({
refresh() {
if(bScroll) {
bScroll.refresh();
bScroll.scrollTo(0.0); }}}));const PullUpdisplayStyle = pullUpLoading ? { display: ""}, {display: "none" };
const PullDowndisplayStyle = pullDownLoading ? { display: ""}, {display: "none" };
return (
<ScrollContainer ref={scrollContaninerRef}>{props. Children} {/* Slide to the bottom to load animation */}<PullUpLoading style={ PullUpdisplayStyle} ></PullUpLoading>{/* Top drop-down refresh animation */}<PullDownLoading style={ PullDowndisplayStyle} ></PullDownLoading>
</ScrollContainer>
);
})
Scroll.defaultProps = {
direction: "vertical".click: true.refresh: true.onScroll: null.pullUpLoading: false.pullDownLoading: false.pullUp: (a)= > {},
pullDown: (a)= > {},
bounceTop: true.bounceBottom: true
};
Scroll.propTypes = {
direction: PropTypes.oneOf(['vertical'.'horizental']),
refresh: PropTypes.bool,
onScroll: PropTypes.func,
pullUp: PropTypes.func,
pullDown: PropTypes.func,
pullUpLoading: PropTypes.bool,
pullDownLoading: PropTypes.bool,
bounceTop: PropTypes.bool,// Whether to support upward suction
bounceBottom: PropTypes.bool// Whether to support upward suction
};
export default React.memo(Scroll);
Copy the code
2. Dynamic loading components
import React from 'react';
import styled, {keyframes} from 'styled-components';
import style from '.. /.. /assets/global-style'
const dance = keyframesTransform: scaleY(0.4); transform-origin: center 100%; } 20%{ transform: scaleY(1); } `
const Loading = styled.div`
height: 10px;
width: 100%;
margin: auto;
text-align: center;
font-size: 10px;
>div{
display: inline-block;
background-color: ${style["theme-color"]};
height: 100%;
width: 1px;
margin-right:2px;
animation: ${dance}1s infinite; } >div:nth-child(2) {animation-delay: -0.4s; } >div:nth-child(3) {animation-delay: -0.6s; } >div:nth-child(4) {animation-delay: -0.5s; } >div:nth-child(5) {animation-delay: -0.2s; } `
function LoadingV2() {
return (
<Loading>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<span>Loading like hell...</span>
</Loading>
);
}
export default LoadingV2;
Copy the code
3. Lazy module loading and code splitting (CodeSpliting)
React provides scenarios for using Lazy and Suspense. The operation is as follows:
import React, {lazy, Suspense} from 'react';
const HomeComponent = lazy((a)= > import(".. /application/Home/"));
const Home = (props) = > {
return (
<Suspense fallback={null}>
<HomeComponent {. props} ></HomeComponent>
</Suspense>)}; . exportdefault[{path: "/".component: Home,
routes: [{path: "/".exact: true.render: (a)= > (
<Redirect to={"/recommend} "/ >) }, { path: "/recommend/", extra: true, key: 'home', component: Recommend, routes:[{ path: '/recommend/:id', component: Album, }] } ...... ] },];Copy the code
5. Future planning and outlook
The core of the project is now complete, but there is still a lot of room for expansion, and the module is only about 60% complete. As for the future planning, I make the following arrangements:
- Finish the function of collecting and playing history at the end of the month
- Complete login function and comment module by October
- Implement MV module by mid-October
- Meanwhile, I wrote a series of disassembly articles titled “Touch hands and Use React to Implement netease Cloud Music webApp”
- More features to add in the future…
As I have other projects to work on, this open source project takes up a large part of my free time, but I think it is worth it, after all, it is a exercise and challenge for myself. What’s more, the significance of this project for me is not only to complete these functions, but to condense my thinking on technology and practice various ideas before. To be honest, when the project was stuck in one place, I almost collapsed inside, but after surviving, I found myself learning a lot of things, full of sense of achievement, which is the deepest feeling of my independent open source project.
Finally, I would like to thank those who helped me and the project, so that I have the confidence to start this project, overcome the difficulties one by one.
Thanks to Huang Yi senior VUE music practice course, let me learn a lot of native JS skills and component packaging skills.
Thanks to Danielle Act for getting me started with React and developing the code habit of React engineering.
Thanks to the React open source project Manmango – Music. Although my current project is completely different from it in terms of development concept and coding style, some animation effects are still borrowed from this open source project, which greatly opens my eyes. Thank you very much. But it’s worth learning.
Finally, this project is by no means a temporary demo, and I will maintain it for a long time. I hope everyone can actively mention PR and issue, so as to make this project more perfect, so as to help more people learn the practical application of React in addition to the official demo and avoid more pitfalls.
In fact, the result of this project is quite natural, but the development process is quite tortuous. I will continue to share the challenges I encountered in the development process with you one by one. Finally, don’t forget to give this project a star, thank you for your support.
Github source address
Finally, I put my wechat official number: Front-end Sanyuan student