首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >超性感的React Hooks(九)useContext实践

超性感的React Hooks(九)useContext实践

作者头像
用户6901603
发布于 2020-07-27 08:58:52
发布于 2020-07-27 08:58:52
1.5K00
代码可运行
举报
文章被收录于专栏:不知非攻不知非攻
运行总次数:0
代码可运行

如上图所示。

我们利用useContext来实现这个小demo。在实现之前,复习一下相关比较重要的知识点。

如下图。

1

如何合理的拆分组件?

这是一个需要在实践中,不断去总结,优化才能获得的技能。

首先,将一个复杂的页面逻辑进行拆分的目的,一定是为了可读性和可维护性。如果你的组件拆分违背了这两个原则,那么拆分就有问题。

本来我想根据我自己的经验,将组件分为基础组件,工具组件,容器组件,页面组件等大类,但是强行引入这些概念并不利于学习,还是建议大家自己在实践过程中去总结适合自己的拆分思维。

不过,有一些原则可以分享给大家

1.当一个组件行数过长,例如超过150行,就应该反思组件是否合理2.页面组件应该逻辑简单,一目了然3.复用程度高的功能/模块可以定义成一个组件4.避免过度拆分,对阅读带来困扰5.合理处理组件的状态,该状态仅在该组件使用,则无需定义在父级

组件的拆分,是考验我们React水平的重要标准,但这不是通过一篇两篇文章就能够马上掌握的技能,因此多给自己一点耐心,多从实践中反复思考总结是非常好的进步方式。

2

首图展示了我们想要实现的页面效果。建议大家先自己尝试实现,再参考我的实现思路进行对比。这样更有利于掌握知识。

首先我们肯定要先思考如何进行组件拆分。

一、通过观察我们发现,一定会有共享的数据,因此我们可以利用context自定义一个Provider的顶层父组件。

二、Tab切换,可以封装成为一个工具组件。但是由于我们的实现效果相对简单,这个地方也只使用一次,因此我选择直接实现。如果放在大型项目中,即使实现比较简单,也应该封装成为一个组件,以供其他页面复用。

三、共有三个Tab页,每一个Tab页都有各自的内容。因此这三个页面应该各自封装成独立的组件。

四、首页模块有一个轮播图功能,这个我们也应该考虑封装为一个工具组件

五、设置模块的步进器可以封装成为一个基础组件

这样梳理下,这个Demo的组件主要结构就应该如下:

3

接下来一个非常重要的思考,就是哪些状态应该在什么组件下来维护。

这一点非常重要,很少有人能够把这个事情做正确。混乱的状态管理,导致了代码非常糟糕。本来很简单的逻辑,可维护起来非常痛苦。太多的人没有去思考这个问题。

在顶层组件Provider中,我们只关心会被不同组件共享的数据。经过分析发现,只有首页和热门的未读标记数字,需要放在Provider中来处理。页面组件App和设置组件Setting都会使用到它们。

其他组件的状态都仅仅只是当前组件自己使用,因此就在各自的组件里维护就行了。

理清了这些思路,实现起来将会非常简单。

4

创建顶层组件Provider,该组件仅仅只维护两个未读的数据。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { createContext, useState, Dispatch, ReactNode } from 'react';

interface Injected {
  unreadIndex: number,
  setUnreadIndex: Dispatch<any>,
  unreadHot: number,
  setUnreadHot: Dispatch<any>,
}

export const ctx = createContext<Injected>({} as Injected);

interface Props {
  children?: ReactNode
}

export function Provider({children}: Props) {
  const [unreadIndex, setUnreadIndex] = useState(0);
  const [unreadHot, setUnreadHot] = useState(0);

  const value = {
    unreadIndex,
    setUnreadIndex,
    unreadHot,
    setUnreadHot,
  }

  return (
    <ctx.Provider value={value}>{children}</ctx.Provider>
  )
}

接下来创建页面组件App,该组件会引入三个Tab页组件,并实现tab切换功能。还需要显示未读的状态。实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, {useContext, useState} from 'react';
import {ctx, Provider} from './context';
import {Badge} from 'antd-mobile';
import Home from './components/Home';
import Hot from './components/Hot';
import Setting from './components/Setting';
import './index.scss';
function App() {
  const {unreadIndex, unreadHot} = useContext(ctx);
  const [tabIndex, setTabindex] = useState(0);

  return (
    <div className="use_context_container">
      <div className="tab_wrapper">
        <Badge text={unreadIndex} style={{ marginLeft: 42 }}>
          <div onClick={() => setTabindex(0)}>首页</div>
        </Badge>

        <Badge text={unreadHot} style={{ marginLeft: 42 }}>
          <div onClick={() => setTabindex(1)}>热门</div>
        </Badge>

        <div onClick={() => setTabindex(2)}>设置</div>
      </div>

      <div className="content_wrapper">
        {tabIndex === 0 && (
          <Home />
        )}

        {tabIndex === 1 && (
          <Hot />
        )}

        {tabIndex === 2 && (
          <Setting />
        )}
      </div>
    </div>
  )
}

export default () => (
  <Provider>
    <App />
  </Provider>
)

Home组件通过知乎日报的接口请求到数据,并展示出来。除此之外,还需要重置Home的未读数字。因此需要借助useContext来访问setUnreadIndex,将对应的状态重置。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { useState, useEffect, useContext } from 'react';
import {zhLastFeedApi, Feed} from './api';
import { ActivityIndicator, Carousel } from 'antd-mobile';
import {ctx} from '../../context';
import './style.scss';

// 执行如下指令,禁用chrome跨域限制
// open -a "Google Chrome" --args --disable-web-security  --user-data-dir

export default function ZhihuFeed() {
  const [feed, setFeed] = useState<Feed>();
  const {setUnreadIndex} = useContext(ctx);

  useEffect(() => {
    setUnreadIndex(0);
    zhLastFeedApi().then(res => {
      setFeed(res);
    });
  }, []);

  if (!feed) {
    return <div className="feed_container loading"><ActivityIndicator /></div>
  }

  const {stories, top_stories} = feed;

  return (
    <div className="feed_container">
      <Carousel infinite autoplay dots={false}>
        {top_stories.map((item, i) => (
          <a className="top_feed_item" key={i} href={item.url} style={{backgroundImage: `url(${item.image})`}}>
            <div className="title">{item.title}</div>
          </a>
        ))}
      </Carousel>

      <div className="inner">
        {stories.map((item, i) => (
          <a className="feed_item" href={item.url} key={i}>
            <img src={item.images![0]} alt=""/>
            <div className="info">
              <div className="title">{item.title}</div>
              <div className="tip">{item.hint}</div>
            </div>
          </a>
        ))}
      </div>
    </div>
  )
}

Hot组件与Home组件逻辑几乎一样,访问博客园的接口并展示数据。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { useState, useEffect, useContext } from 'react';
import {topViewApi} from './api';
import { ActivityIndicator } from 'antd-mobile';
import { ctx } from '../../context';
import './style.scss';
// 执行如下指令,禁用chrome跨域限制
// open -a "Google Chrome" --args --disable-web-security  --user-data-dir

export default function ZhihuFeed() {
  const [feed, setFeed] = useState<string>();
  const {setUnreadHot} = useContext(ctx);

  useEffect(() => {
    setUnreadHot(0);
    topViewApi().then(res => {
      setFeed(res);
    })
  }, []);

  if (!feed) {
    return <div className="feed_container loading"><ActivityIndicator /></div>
  }

  return (
    <div className="blog_container" dangerouslySetInnerHTML={{__html: feed}}>
    </div>
  )
}

Setting组件需要设置unread的数字,因此状态从Provider中来。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { useContext } from 'react';
import { List, Stepper } from 'antd-mobile';
import {ctx} from '../../context';
import './index.scss';

export default function Setting() {
  const {unreadIndex, unreadHot, setUnreadIndex, setUnreadHot} = useContext(ctx);

  return (
    <div className="setting_container">
      <div className="title">基本设置</div>
      <List>
        <List.Item wrap extra={
          <Stepper
            showNumber
            min={0}
            value={unreadIndex}
            onChange={setUnreadIndex}
          />}
        >
          首页未读
        </List.Item>
        <List.Item extra={
          <Stepper
            showNumber
            min={0}
            value={unreadHot}
            onChange={setUnreadHot}
          />}
        >
          热门未读
        </List.Item>
      </List>

      <div className="tip">该设置项仅仅用于展示context功能,实践中几乎不会有这样的需求,不过需要使用相同处理方式的需求很多</div>
    </div>
  )
}

这样,一个看上去比较复杂的案例,就简单的实现了。

很少有人能够把思路理到如此清晰,这,也正是你超越他人的机会所在。

本系列文章的所有案例,都可以在下面的地址中查看

https://github.com/advance-course/react-hooks

本系列文章为原创,请勿私自转载,转载请务必私信我

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 不知非攻 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
流计算 Oceanus 操作效率提升指南一
为了避免用户机械重复的对作业进行某一类操作,前端支持了五种快捷高效的批量操作。分别是批量启动、停止、删除、创建副本、移动。操作入口如下图。
xianyulli
2022/05/23
1.1K0
数据开发治理平台Wedata之数仓建设实践
本案例基于腾讯云一站式开发治理平台Wedata、私有网络VPC、云数据库Mysql和弹性Mapreduce构建了全流程的离线数仓建设流程。通过模拟业务数据的导入,分层ETL和数据应用全过程,演示了如何在Wedata上进行高效的数据开发与治理。
张志刚
2022/05/07
3K0
拥有QcloudCamFullAccess策略,却提示我 no permission
做为子账号的拥有者,由于工作关系经常要使用到腾讯云的各种产品,厚着脸皮和管理员要到了【QcloudCamFullAccess】策略权限,想着后续工作起来会比较方便,但是主账号管理员在明确给我fullaccess后,我发现我依然无法自主配置使用CAM,BBQ了。。。。
joeexu
2022/04/11
6960
Snova添加子用户及策略操作指南1
在用户列表中,选择需要授权的子用户。关联snova相关读写权限。策略关联成功后,子用户即获取相关资源权限。
Snova官方账号
2018/08/15
7040
CAM授权协作者账号操作CVM
https://console.cloud.tencent.com/cam/policy
高鹏-bryan
2020/04/04
1.3K0
CAM授权协作者账号操作CVM
【技术种草】我用 1个肉夹馍的钱,搭了整套大数据系统
下面我分享一下如何用 1 个肉夹馍的钱来搭建一套云上的大数据平台。经过本人反复的钻研,发现薅羊毛这件事简直是太简单了。最后买 MySQL 19.9元,流计算 Oceanus(Flink) 1 元,花了二十几块钱,搭建了这样式的大数据系统。
吴云涛
2021/11/25
4.6K3
【技术种草】我用 1个肉夹馍的钱,搭了整套大数据系统
实时数仓:基于流计算 Oceanus 实现 MySQL 和 HBase 维表到 ClickHouse 的实时分析
实时即未来,最近在腾讯云流计算 Oceanus(Flink) 进行实时计算服务分享给大家~
吴云涛
2021/12/21
2.3K0
实时数仓:基于流计算 Oceanus 实现 MySQL 和 HBase 维表到 ClickHouse 的实时分析
EventBridge 最佳实践场景:流计算 Oceanus 告警消息实时推送
作者:腾讯云云函数团队产品经理April 导语|本文演示了如何捕获流计算 Oceanus (Flink) 集群状态变更,并通过事件总线(EventBridge)发送到企业微信或钉钉、飞书客户端。 背景介绍 监控与报警系统对于业务生产环境来说是不可或缺的,一旦有故障发生,需要有完善的监控告警链路,保证告警消息可以实时完成推送并进行处理。 腾讯云事件总线(EventBridge)[1] 简称 EB,是一款安全、稳定、高效的无服务器事件管理平台。事件中心的事件总线可以接收来自您自己的应用程序、软件即服务(Sa
腾讯云大数据
2022/01/07
1K0
CDN如何给子账号授权预热权限
内容分发网络(CDN)接入了腾讯云云资源访问管理(Cloud Access Management)系统,您可以在 访问管理 控制台进行用户组、用户、角色、策略等一系列相关管理操作。
用户2553168
2019/11/06
3.1K0
实时监控:基于流计算 Oceanus(Flink) 实现系统和应用级实时监控
本文描述了如何使用腾讯云大数据组件来完成实时监控系统的设计和实现,通过实时采集并分析云服务器(CVM)及其 App 应用的 CPU和内存等资源消耗数据,以短信、电话、微信消息等方式实时反馈监控告警信息,高效地保障系统稳健运行。运用云化的 Kafka、Flink、ES 等组件,大大减少了开发运维人员的投入。
吴云涛
2021/09/09
6.7K3
实时监控:基于流计算 Oceanus(Flink) 实现系统和应用级实时监控
基于流计算 Oceanus 和 Elasticsearch 构建日志分析系统
实时即未来,最近在腾讯云流计算 Oceanus(Flink)进行实时计算服务,以下为MySQL 到 Flink 进行处理分析,再存储到ES的实践。分享给大家~
吴云涛
2021/08/09
1.1K0
基于流计算 Oceanus 和 Elasticsearch 构建日志分析系统
使用ACL,轻松管理对存储桶和对象的访问!
访问控制与权限管理是腾讯云对象存储 COS 最实用的功能之一,经过开发者的总结沉淀,已积累了非常多的最佳实践。读完本篇,您将了解到如何通过ACL,对存储桶和对象进行访问权限设置。
云存储
2020/05/26
2.5K0
使用ACL,轻松管理对存储桶和对象的访问!
教你如何使用vercel服务免费部署前端项目和serverless api
使用GitHub账号去关联vercel,后续代码提交到vercel可以自动触发部署
前端进阶之旅
2022/01/04
3.5K0
教你如何使用vercel服务免费部署前端项目和serverless api
实时监控:基于流计算 Oceanus ( Flink ) 实现系统和应用级实时监控
---- 作者:吴云涛,腾讯 CSIG 高级工程师 本文描述了如何使用腾讯云大数据组件来完成实时监控系统的设计和实现,通过实时采集并分析云服务器(CVM)及其 App 应用的 CPU和内存等资源消耗数据,以短信、电话、微信消息等方式实时反馈监控告警信息,高效地保障系统稳健运行。运用云化的 Kafka、Flink、ES 等组件,大大减少了开发运维人员的投入。 一、解决方案描述 (一)概述 本方案结合腾讯云 CKafka、流计算 Oceanus (Flink)、 Elasticsearch、Promethe
腾讯技术工程官方号
2021/10/14
2.5K0
限制子账号/API秘钥使用固定IP访问(IP白名单)
业务实际场景下,云API秘钥是固定在某些机器上跑,基于安全考虑,可以限制只允许固定的IP能调用API访问。
邪恶の大灰
2025/04/01
2530
限制子账号/API秘钥使用固定IP访问(IP白名单)
账号管理实践 - 通过CAM限制子账号权限
腾讯云提供了访问管理(CAM)来帮助客户实现权限管理,借助CAM可实现权限的精细化控制和高效管理,
本地专用集群CDC
2022/11/16
5.1K0
基于流计算 Oceanus 和 Elasticsearch Service 实现实时监控系统
本文描述了如何使用腾讯云大数据组件来完成实时监控系统的设计和实现,通过实时采集并分析云服务器(CVM)及其 App 应用的 CPU 和内存等资源消耗数据,高效地保障系统稳健运行。运用云化的 Kafka、Flink、ES 等组件,大大减少了开发运维人员的投入。
于乐
2021/11/18
1.2K0
基于流计算 Oceanus 和 Elasticsearch Service 实现实时监控系统
snova子账号操作指南1
在用户列表中,选择需要授权的子用户。关联snova相关读写权限。策略关联成功后,子用户即获取相关资源权限。
腾讯云数据工坊TDF
2018/08/15
1.5K0
指标统计:基于流计算Oceanus(Flink) 实现实时UVPV统计
导语 | 最近梳理了一下如何用Flink来实现实时的UV、PV指标的统计,并和公司内微视部门的同事交流。然后针对该场景做了简化,并发现使用Flink SQL来实现这些指标的统计会更加便捷。 一、解决方案描述 (一)概述 本方案结合本地自建Kafka集群、腾讯云流计算Oceanus(Flink)、云数据库Redis对博客、购物等网站UV、PV指标进行实时可视化分析。分析指标包含网站的独立访客数量(UV)、产品的点击量(PV)、转化率(转化率=成交次数/点击量)等。 相关概念介绍: UV(Unique
腾讯云开发者
2021/10/22
1.2K0
腾讯云临时秘钥方案-文字识别示例
腾讯云官网的SecretId 和 SecretKey是属于您的重要财产。在使用OCR业务时需要利用SecretId 和 SecretKey去进行认证签名计算,但是如果将SecretId 和 SecretKey写死在SDK的代码当中存在极大的泄露风险。因此,我们在支持使用固定密钥的同时,提供了一种使用临时密钥的方式。SDK可以使用临时密钥进行认证签名计算,去请求OCR识别接口。兑换的临时密钥具有时效性,可以大大降低SecretId 和 SecretKey泄露的风险。
HI hero
2021/11/03
3.8K0
推荐阅读
相关推荐
流计算 Oceanus 操作效率提升指南一
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档