Hands-on to teach you: entry-level React imitation Xiaohongshu homepage

image.png

foreword

Introduction to React

  React is a JavaScript library for building user interfaces, mainly for building UI. React has high performance and features like JSX (which is an extension of JavaScript) and components. The idea of ​​componentization is widely used in React, and the code can be well reused by constructing components. In addition, React 's declarative design and its emulation of the DOM make it efficient and flexible.

project description

  As an app positioned in social && e-commerce , Xiaohongshu has attracted more and more attention in recent years, and its user base is also expanding. As a user of Xiaohongshu, combined with the recent knowledge of React , I have the idea of ​​using React to imitate the homepage of Xiaohongshu. This project realizes the basic page of the homepage of Xiaohongshu, and then takes you to the project display and actual combat.

Finished product display

here is the image

image.png


Made a mistake, come back

QQ screen recording 20220705164119.gif


Project combat

Initial stage

Create a React project   in Vscode. There are many ways to create a project. Use the official scaffolding create-react-app or Webpack to create. Here I use the Vitejs method to create it, which is much faster than other methods. If you are interested in this, I will write an article about Vite and Webpack later. Your likes and support are the source of my continuous creation ღ( ´・ᴗ・` )

folder configuration

  After the project is created, the next step is to clean up the code in the related files and related redundant files, and then create the most basic folders in the project.

  • api folder for network requests
  • The assets folder is used to store some static resources such as icons and pictures
  • pages folder for pages
  • commpents folder for reusable components

  More detailed file directories are as follows:

image.png

Dependency installation

  相关文件夹配置完成后,可以开始安装项目需要的依赖

  • npm i axios   用于获取后端数据
  • npm i react-router react-router-dom    用于项目路由跳转
  • npm i styled-components   用于实现Css in JS
  • npm i antd-mobile   一个好用的UI组件库
  • npm i classname   用于添加多个类名

  安装成功后如下所示:

image.png

组件及页面分析

路由介绍

  在以上工作完成后,接下来就是搭建相关路由了,路由在项目中是十分重要的。Route【路由】可以理解为现实中路由器后面的接口,Routes【路由器】可以理解为现实的路由器用来管理路由。在此项目中,我设置了如下几个路由:

const Home = lazy(() => import('./pages/Home'))
const Mine = lazy(() => import('./pages/Mine'))
const Message = lazy(() => import('./pages/Message'))
const Shop = lazy(() => import('./pages/Shop'))
const Choose = lazy(() => import('./pages/Choose'))

<Routes>
        <Route path="/" element={<Home/>}></Route>
        <Route path="/home" element={<Home/>}></Route>
        <Route path="/mine" element={<Mine/>}></Route>
        <Route path="/message" element={<Message/>}></Route>
        <Route path="/shop" element={<Shop/>}></Route>
        <Route path='/choose' element={<Choose />}></Route>
</Routes>

  路由搭建需要注意以下几点:

  • main.jsx中引入{BrowserRouter}方能正常使用
  • 使用路由懒加载,可提升加载速度,需引入{Suspense}

image.png

  • 若出现某个页面跳转后不显示底部导航栏,可以通过简单的条件判断和{useLocation}接受传来的值来实现。比如如下所示:
import {useLocation} from 'react-router-dom'

const {pathname}=useLocation()
if (pathname == '/choose') return

数据请求

  在此项目中采用的是fastmock来请求与管理数据,然后在api文件夹中创建request.js来获取数据。后续在相关页面中引入即可。

image.png

import axios from 'axios'

export const Getlist = () =>   
axios.get
('https://www.fastmock.site/mock/33e7fec4e60b54344eaa2c59a55b379d/red_book/red_book/list')
export const Getfood = () =>   
axios.get
('https://www.fastmock.site/mock/33e7fec4e60b54344eaa2c59a55b379d/red_book/red_book/food')

底部导航栏

QQ录屏20220705171130.gif


  底部导航栏通过路由的切换来实现。上面已经讲过一些路由知识,在此就不做过多描述。在components文件夹中创建Footer组件,用于底部导航栏。在此注意点击中间加号跳转后底部导航栏不会一起跳转,因此需要做相关判断来实现跳转新页面,源码如下:
Footer.jsx

import React from 'react'
import {Link,useLocation} from 'react-router-dom'
import {FooterWrapper} from './style' 
import classnames from 'classnames'
import { Badge } from 'antd-mobile'

function Footer(props) {
  const {pathname}=useLocation()
  if (pathname == '/choose') return
  return (
    <FooterWrapper>
      <Link to="/" className={classnames({active:pathname == '/'})}>
      <span>首页</span>
      </Link>
      <Link to="/shop" className={classnames({active:pathname == '/shop'})}>
      <span>商城</span>
      </Link>
      <Link to="/choose" className={classnames({active:pathname == '/choose'})}>
      <span><i className="iconfont icon-Addtianjia3"></i></span>
      </Link>
      <Link to="/message" className={classnames({active:pathname == '/message'})}>
      <Badge content='5'><span>消息</span></Badge>
      </Link>
      <Link to="/mine" className={classnames({active:pathname == '/mine'})}>
      <span>我</span></Link>
    </FooterWrapper>
  )
}

export default Footer

  主页面引入Footer,部分源码如下:

<>
<Routes>
        <Route path="/" element={<Home/>}></Route>
        <Route path="/home" element={<Home/>}></Route>
        <Route path="/mine" element={<Mine/>}></Route>
        <Route path="/message" element={<Message/>}></Route>
        <Route path="/shop" element={<Shop/>}></Route>
        <Route path='/choose' element={<Choose />}></Route>
</Routes>
<Footer />
</>

顶部导航栏

QQ录屏20220705171330.gif


  The top navigation bar uses the Tab bar to switch content. There are two navigation bars here, and there is also a navigation bar under the discovery page, so you need to implement the navigation bar effect twice. The implementation of the two navigation bars is very simple, the source code is as follows:
Home .jsx

import React, { useState,useEffect } from "react";
import { Tabs,Popup } from 'antd-mobile'
import Care from './Care'
import Find from './Find'
import City from './City'
import Search from '../Search'
import Daily from '../Daily'
import './style.css'

 const Home = () =>{
    const [visible1, setVisible1] = useState(false)
    const [visible2, setVisible2] = useState(false)
    return(
        <div>
            <Tabs defaultActiveKey='find' style={
                {'--active-line-color':'#ed2b43','--active-title-color':'#000000'}}>
                <Tabs.Tab title='关注' key='care'>
                    <Care/>
                </Tabs.Tab>
                <Tabs.Tab title='发现' key='find'>
                    <Find/>
                </Tabs.Tab>
                <Tabs.Tab title='城市' key='city'>
                    <City/>
                </Tabs.Tab>
            </Tabs> 
            
            <span
              onClick={() => {
                setVisible1(true)
              }}
            >
              <i className="iconfont icon-yuzhouxingqiu-12"></i>
            </span>
            <Popup
              visible={visible1}
              onMaskClick={() => {
                setVisible1(false)
              }}
              position='left'
              bodyStyle={{ height: '100%',width:'100%' }}
            >
              {<Daily />}
            </Popup>
            <span
              onClick={() => {
                setVisible2(true)
              }}
            >
              <i className="iconfont icon-sousuo"></i>
            </span>
            <Popup
              visible={visible2}
              onMaskClick={() => {
                setVisible2(false)
              }}
              position='right'
              bodyStyle={{ height: '100%',width:'100%' }}
            >
              {<Search />}
            </Popup>
        </div>
    )
 }

 export default Home

Find.jsx

import React, { useState,useEffect } from "react";
import { Tabs,Collapse,SpinLoading } from 'antd-mobile'
import Recommend from '../../Recommend'
import Video from '../../Video'
import Liver from '../../Liver'
import Food from '../../Food'
import { Getlist } from '../../../api/request'
import { Getfood } from "../../../api/request"
import './style.css'

 const Find = () =>{

  const [list,SetList] = useState([])
    useEffect(()=>{
      (async() => {
        let { data } = await Getlist()
        SetList(data)
      })()
    },[])
    const [food,SetFood] = useState([])
    useEffect(()=>{
      (async() => {
        let { data } = await Getfood()
        SetFood(data)
      })()
    },[])

    return(
        <div>
        <Tabs defaultActiveKey='1' style={
          {'--title-font-size':'15px','--active-line-height':'0px',
          '--active-title-color':'#ed2b43'}}>
          <Tabs.Tab title='推荐' key='1'>
            {list.map(item=>(
              <Recommend source={item} key={item.id}/>
            ))
              }
          </Tabs.Tab>
          <Tabs.Tab title='视频' key='2'>
            <Video/>
          </Tabs.Tab>
          <Tabs.Tab title='直播' key='3'>
            <Liver />
          </Tabs.Tab>
          <Tabs.Tab title='美食' key='4'>
            {food.map(item=>(
              <Food entry={item} key={item.id}/>
            ))
              }
          </Tabs.Tab>
          <Tabs.Tab title='知识科普' key='5'>
           .........
          </Tabs.Tab>
           .........
            此后代码大致相同,便在此处省略
        </Tabs>
        <SpinLoading style={{'--color':'#ed2b43'}} className="load"/>     
        </div>
    )
 }

 export default Find

  The Tab bar in this project uses the Tab bar packaged in antd-mobile, refer to the documentation in antd-mobile, and then introduce the relevant components, you can use it. Although it is more convenient to use, because it is a packaged component, the modification of some styles will be more limited. To modify the style, you can refer to the document to modify the related style or add the className class name to redefine the related style. The relevant website is attached below. Interested friends can refer to the relevant documents. This is a good UI component library.
Ant Design Mobile - Ant Design Mobile

Home content

QQ录屏20220705164119.gif


  The home page is the main page of this project. After entering this page, related functions such as page jumping can be realized. The data on the page is stored in fastmock. Then in the Recommend and Food pages, the required data is obtained on the page by traversing. In addition, jump to the search page, and the search box used in it is also the Search packaged in antd-mobile. You can modify the style slightly and then call it directly. For icons, using icons from iconfont is sufficient for most needs. Introduce the font folder with the icons added in advance in the assets folder, and then you can easily modify the icon style in the font folder. Part of the source code is as follows:

Search.jsx

import React from "react";
import { NavBar,SearchBar } from "antd-mobile";
import {Link} from "react-router-dom"
import './style.css'

 const Search = () =>{
    return(
        <div>
            <Link to='/shop'>
           <NavBar>
                <SearchBar 
                className="searchbar"
                placeholder='请输入内容'
                style={{
                    '--border-radius': '100px',
                    '--background': '#f5f5f5',
                    '--height': '30px',
                    '--placeholder-color':'#afafaf',    
                }}
                />
                <span className="search">搜索</span>
            </NavBar>
            </Link>
        </div>
    )
 }

 export default Search

Recommend.jsx

import React from "react";
import './style.css'

 const Recommend = ({source}) =>{
    const {img,content,author,icon} = source  
    return(
        <div className="List">
          <img src={img} className="list-img" />
          <div className="list-content">{content}</div>
          <div className="list-author">
            <img src={icon} className="icon-img"></img>
            <div className="list-h">{author}</div>
            <i className="iconfont icon-dianzan"></i>
          </div>
        </div>
    )
 }

 export default Recommend

Food.jsx

import React from "react";
import './style.css'

 const Food = ({entry}) =>{
    const {img,content,author,icon} = entry  
    return(
        <div className="List">
          <img src={img} className="list-img" />
          <div className="list-content">{content}</div>
          <div className="list-author">
            <img src={icon} className="icon-img"></img>
            <div className="list-h">{author}</div>
            <i className="iconfont icon-dianzan"></i>
          </div>
        </div>
    )
 }

 export default Food

Summarize

  This is a preliminary project, and there are many functions and related components that have not been fully realized. Later, with the in-depth study and mastery of React knowledge, this project will be modified and improved, and will continue to be published. If there are any optimizations or mistakes, you are welcome to point them out in the comment area. Finally, if this article can help you, thank you for your likes ღ( ´・ᴗ・` )

Guess you like

Origin juejin.im/post/7116817540055040013