Demostración de combate React "Hands-on Series 2": encapsulación de solicitudes de red/implementación de búsqueda (antivibración)/carga diferida/useMemo()/gestión de flujo de datos redux/página de inicio

I. Introducción

Este proyecto es para react新手入门una demostración de 星巴克componentes de imitación. Si puede ayudarlo, proporcione uno pequeño 点赞. En segundo lugar, este proyecto utiliza el código del 神三元tipo grande en el react-cloud-musicproyecto de código abierto: código fuente de react-cloud-music , react-cloud -folleto de música para explicar . 工具组件Voy a explicar algunos de ellos utilizados .

1.0, tonterías

  • Principalmente quiero integrar algunos conocimientos en mi propio proyecto (comprensión) en la forma de aprender el proyecto del jefe. Tiene 网络请求una actualización relativamente grande desde el primer episodio del proyecto. Las otras páginas originales solo se actualizan con reduxdatos. gestión de flujo. Si está interesado, puede 收藏o关注专栏

1.1 Visualización del proyecto y dirección del proyecto

todo.gif

  • En cuanto al estilo, con el fin de ponerse al día con el trabajo, no se ha hecho bien rem适配. Después de que se publique el artículo, se acelerará la 修改adaptación .
  • Si es posible, asigne una estrella al soporte: código fuente del proyecto github
  • Si es posible, dé una estrella para respaldarlo: código fuente del proyecto gitee

1.2 Contenido de esta actualización

  • Hacer la encapsulación de la solicitud de red.api/config
  • Estabilización de imagen de plato de búsqueda ( debounce)
  • Carga diferida de la página del menú ( lazy-load)
  • Actualice reduxDFM (no me pregunte por qué lo sigo usando redux)
  • Lista de búsquedas populares durante la búsqueda ( hotlist)
  • Implementación del carrusel de la página de inicio ( swiper)

2. Reducción

2.0, diseño técnico

  • Esta actualización reduxno ha cambiado más que las cosas nuevas.
  • 相较于第一集,网络请求方面有较大的变化

2.1、理解redux(从useState过渡)

redux.jpg

reduxshow.gif

  1. 首先我不得不说,这个项目的数据量根本不至于用到redux,但是为了更好的理解redux,我还是把他加到了这个项目当中,那么我们要如何从原来在页面中通过useState()定义数据的初始状态,以及改变的setXXX()函数,到现在的redux数据流管理?
  2. 从页面的useState的思想中跳出来,当我们开发一个大型项目的时候,不可能把数据放在当前要运行的页面,这样不利于协同开发,页面多了数据也无法管理,所以我们用一个公共的数据仓库存一下页面所涉及的数据
  3. 当前页面要发生状态变化的时候,当前页面打一个电话给storestore收到了要变化的条件,返回给页面对应的状态,从而实现MVVM(具体实现中间还有很多过程,为了便于理解这么讲)。
  • Store:Store 就是保存数据的地方,你可以把它看成一个容器。
  • State:Store对象包含所有数据。如果在某个页面数据,就要对 Store 生成快照。
  • Action:在原来的useState中,State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。
  • ActionCreators:指明Action变化的种类
  • dispatch():是 View 发出 Action 的唯一方法。
  • Reducer:Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。

三、项目实现

3.0、封装网络请求

  • 上次我们把数据过滤放在数据请求里,这样请求一多,request文件会变得很复杂
  • 为了在代码上线时候可以快速修改localhost:3000服务器端url我们进行了一层封装,实现request.config
    {/*代码实现*/}
    // 配置请求对象
    import axios from 'axios'
    // 本地调试 dev 开发阶段,baseurl为远程基础url
    export const baseUrl = "https://www.fastmock.site/mock/5321bf649d06645c4266f3e0d45ae1cc";
    const axiosInstance = axios.create({
        baseURL: baseUrl
    })
    axiosInstance.interceptors.response.use(
        res => res.data,
        err => {
            console.log(err, '网络错误~~')
        }
    )
    export { axiosInstance }
    
    {/*代码实现*/}
    import axios from 'axios'
    import { axiosInstance } from "./config";
    export const getMenuListRequest =
        () => axiosInstance.get('/menu/all')
    export const getHotListRequest =
        () => axiosInstance.get('/menu/hot')
    

3.1、实现搜索+防抖+useMemo

debounce.gif

  • 这里把搜索懒加载放到0.8s实现搜索一次,效果明显一点,如果是自己写项目,0.3左右即可,太长用户体验不好
  • 搜索防抖的实现工具类随处可见,如果想自己实现的话可以参考下面的代码,甚至可以直接用lodash中的`debounce
  • 搜索实现
    1. 这里我仿造神三元大佬在其项目中的搜索,最外层用了一个Search组件,内层用SearchBox包了一层
    2. Search组件有一个query变量(便于理解我们叫他fatherQuery),和一个handleQuery函数用于修改fatherQuery
    3. SearchBox组件有自己的query(便于理解我们叫他sonQuery),同时接收传进来的Search中的fatherQueryhandleQuery
    4. SearchBox中修改的sonQuery,进行防抖处理,每隔800毫秒,执行一次handleQuery去修改Search中的fatherQuery ,因为最后是fatherQuery执行dispatch改变状态
    //父组件Search
    function Search(props) {
        const {hotList,suggestList} = props;
        const {getHotKeyMenuDispatch,getSuggestMenuDispatch} = props
        //这个useEffect只有每隔800ms才会得到重新渲染的机会
        useEffect(()=>{
            getSuggestMenuDispatch(query);
        },[query])
        //用于在子组件searchBox执行,更新父组件的query
        //但是子组件有防抖,需要每隔800ms执行一次
        const handleQuery = (q) =>{
            setQuery(q)
        }
        return( 
            <>
                <SearchBox newQuery={query} handleQuery={handleQuery}>
                </SearchBox>
            </>
        )
    }
    
    export default  memo(function SearchBox(props) {
    //得到父组件的变量与函数
    const {handleQuery} = props
    const [query,setQuery] = useState('')
    useEffect(() => {
        //父组件的query去dispatch更新状态
       handleQueryDebounce(query)
    }, [query])
    //防抖
    let handleQueryDebounce =  useMemo(() => {
       return debounce(handleQuery,800)
    }, [handleQuery])
    //返会给父组件query值
    const handleChange = (e) =>{
       let val = e.currentTarget.value
       setQuery(val)
    }
    return (
    <SearchWrapper>
        <div className="search_box">
          <input type="text" className='box' placeholder='搜索菜单' onChange={handleChange}  ref={queryRef}>
          </input>
          <i className='iconfont icon-sousuo' onChange={handleChange}></i>
        </div>
    </SearchWrapper>
       )
    })
    
  • useMemo
    1. 这里是一个很适合用到useMemo的地方,因为当fatherquery改变的时候会触发useEffect重新渲染整个子页面,但是我们handleQuery函数却不用每次都执行,useMemo()会记住这次运行的结果,是一个性能优化的好帮手,在跨页面数据流动减少复杂状态更新的地方常常用到。
    2. 例如网站首页加载了很多图片,但是我们跳到其他页面再回来又需要重新渲染这个页面,十分浪费性能,这种类似的情况就可以用到useMemo()
  • CSSTransition
    1. 这个是用来实现点击搜索后,页面从右到左划过的效果,需要的可以去仓库拉去样式

3.2、懒加载

lazyload.gif

  • 在菜单展示页面和搜索出来的菜品都有lazyload效果
  • lazyload的实现在今天已经非常简单了,以前可能还需要手写判断视口,或者用他人写好的工具库
  • 我们只需要npm i react-lazyload
  • img遍历的过程中加入Lazyload组件,并准备好替换图片放在placeholder
    {/*代码实现*/}
    <div className="good"> 
            {/* lazyload组件,用placeholder存放懒加载时的图片 */}
          <Lazyload placeholder={
            <img width="120%" height="100%"
                src={loading}
            />}>
              <img src={goodItem.img} alt=""/>
          </Lazyload>
          <div className="name">{goodItem.goods}</div>
    </div>
    

3.3、首页

INICIO.gif

  • 首页差不多做到了1:1复刻,但是首页没有什么业务逻辑,所以后续估计也不会更新首页了,会着眼于其他页面的业务进行打造,争取做到一个比较适合前端面试的程度。
  • 轮播图的效果主要是运用了antdswiper组件
  • 如果首页有想了解的样式或者布局可以去仓库拉取。
    const swiper1_img = [img1,img2]
    //items遍历轮播图的图片
    const items = swiper1_img.map((item, index) => (
      <Swiper.Item key={index} >
        <img src={item} alt="" />
      </Swiper.Item>
    ))
    export default function Home() {
      return (
        <Container>
            <LoopImg>
              <div title='循环'>
                  {/*用items占位*/}
                <Swiper loop autoplay className='sw'>{items}</Swiper>
              </div>  
            </LoopImg>
        </Container>
     )}
    

Cuarto, el final

Finalmente, espero que todos no sean tacaños con 1kb y gitee star, lo cual es realmente importante para mí. Espero 谢谢con ansias la próxima actualización para hacer que este proyecto sea más perfecto. Y 神三元大佬los artículos recomendados, si es difícil de entender, puede comprar el suyo 小册, hay un enlace al folleto de instrucciones correspondiente

Estoy participando en el reclutamiento del programa de firma de creadores de la Comunidad Tecnológica de Nuggets, haga clic en el enlace para registrarse y enviar .

Supongo que te gusta

Origin juejin.im/post/7120813140165525535
Recomendado
Clasificación