干货 | 携程火车票Rematch框架实践

从Reset到Read:深入解析Rolling Shutter曝光流水线 本文深入解析Rolling Shutter(卷帘曝光)的工作原理,重点探讨Reset和Read信号在图像传感器中的关键作用。通过Reset-Read流水线机制,详细解释了曝光控制、时序调优及运动伪影补偿等核心技术,帮助读者理解卷帘曝光在高速摄影和动态场景中的应用。 阅读详情

作者简介

 

滨峰,携程开发经理;国春,携程高级开发工程师。

本文主要介绍携程火车票模块在进行新业务开发和老代码重构时,使用rematch状态管理框架的实践经验总结,包括在过程中暴露出来的一系列问题以及相应的解决方案。

一、 背景

携程火车票业务迭代至今,已经实现了全流程的RN化。与此同时,之前基于redux状态管理方式写的业务代码,其中的问题也逐渐显现出来,主要体现在:

1)写法复杂,且状态改变的触发逻辑和处理逻辑很分散,代码可读性较差,新人上手难;

2)组件状态严重依赖于页面,与页面有强耦合,导致页面逻辑复杂难懂,组件也无法得到有效的复用。

问题的根源在于状态管理,于是我们开始尝试寻找新的状态管理方案。rematch作为redux的最佳实践,进入了我们的视线。

Rematch基于redux,进行了封装,简化了redux的使用方式,写同样的逻辑,所需的样板代码更少;且它有全局分发器dispatch,有利于页面和组件之间的解耦。因此,我们使用rematch这种新的状态管理方案,来进行了流程改造。


二、 改造流程设计

为了兼顾日常开发任务,我们将项目rematch化的改造计划分为了三期。

1)第一期:先在新页面中来尝试使用rematch框架,我们找了一个与流程几乎没有什么耦合的新页面来试水。一方面来用来熟悉rematch框架,另一方面也为了测试该框架在项目中的兼容性和稳定性;

2)第二期:火车票详情页使用rematch进行重构,积累一些重构经验,为后面的全流程推广奠定基础;

3)第三期:火车票全流程使用rematch框架。


三、 问题与解决

在实践过程中,我们遇到了很多问题,针对这些问题,我们总结了相关的经验。


3.1 Rematch和Redux的store如何兼容

rematch提供了相关接口,可以在同一个store中,兼容redux,这是一种渐进式的改造过程,适用于在原页面上添加一个使用rematch的新组件。这种方式会使页面处于redux和rematch共存的中间状态,后续还需要进行再次改造,略显麻烦。

我们的做法是,给rematch建立一个新的store,以页面为纬度进行改造。在根组件中,首先获取当前页面的路由。在事先声明的路由与store的映射表中,指定各个页面匹配对应的store,来达到切换store的目的。


3.1.1 配置需要使用新的store页面
const newStorePages = [
    "Page1",
    "Page2"
]

3.1.2 在模块初始化的时候,根据配置表加载不同的store

在页面跳转时拿到初始化页面initialPage。拿到初始化页面以后,根据之前的映射表来判断当前应该使用哪种store,从而保证在一个RN实例中只会存在一个store,实现了两个store在项目中的兼容。

render() {
    ......
    return (
        <Provider store = newStorePages.indexOf(urlQuery.initialPage || "") > -1 ? newStore : store>
            <AppWithContext {...this.props} />
        </Provider>
    )
}

3.2 如何使用Rematch实现模块间完全解耦

在结构复杂、业务多变的互联网产品中,要做到模块具有较强的独立性、易用性、可移植性以及扩展性,那么模块之间完全解耦就显得尤为重要了。完全解耦的终极目的,是在删除、修改、迁移这个模块时,只需要对应地去操作这个模块文件以及这个文件的引用。除此之外,不需要修改任何其他模块、文件,如此即达到了组件最大化解耦。

因此,我们将组件放置在单独的文件夹中,其中包含两个文件index.js 以及 model.js, index文件主要是描述组件视图, model.js里封装了组件所有的逻辑。下面以一个弹窗逻辑为例,看下新老两种方式的对比:


3.2.1 传统方式

1)先在页面中声明一个state去控制组件的显示隐藏

this.state = {
    showManualSpeed: false
}

2)作为属性传入组件

<ManualSpeedLayer
    orderInfo={orderInfo}
    isShow={this.state.showManualSpeed}
    cancel={() => {
        this.setState({showManualSpeed:false})
    }}
/>

3)改变状态去控制组件的显示隐藏

this.setState({
    showManualSpeed: true
})


可以看到,传统方式,主页面和组件之间耦合十分严重,组件的属性都在页面引入时传入,而这些属性页面其实都不用知道,页面只需引用组件就好了。组件的状态变化应该由实际触发其变化的地方去执行,而传统的方式将state都绑定在页面上,使得组件间通信必须经过页面来触发,导致主页面和组件的强耦合。

3.2.2 使用rematch的方式

1)先看看组件的结构

- ManualSpeedPopupView
    - index.js // 组件UI
    - model.js // 组件状态及逻辑

2)在model.js中暴露显示或隐藏弹窗的方法

const manualSpeedLayer = {
    state : false,
    reducers: {
        show(state, playload) {
            return true;
        },
        hide(state, playload) {
            return false;
        }
    },
}

3)使用时,只需要在调用redux的connnect方法引入就可直接显示或隐藏该弹窗。这样能够避免多余的状态声明和管理,而且与父组件完全解耦。

......


const mapState = state => ({
    isShow: state?.manualSpeedLayer 
})
const mapDispatch = ({manualSpeedLayer}) => {
    return {
        hide: () => {manualSpeedLayer.hide()}
    }
}


export default memo(connect(mapState, mapDispatch)(ManualSpeedPopupView))

4)在页面中的引入也变得十分简单

<ManualSpeedPopupView />

Rematch中把state、reducers和异步处理放在了一起,相比于redux的传统写法,这样的写法来的更加简洁方便。组件相关的逻辑都收到了一起,这样页面在引用时,无需再进行多余的状态声明和管理,代码可读性也大大提升。

组件和页面的强耦合,还体现在与组件操作相关的函数中。之前的处理方式,是将页面page传给函数。

export function clickSchoolActivityBtn(page) {
    let {
        orderInfo,
    } = page.props;
    
    ......
    
    page.props.setShowDialog(false);
}

由于状态和action都绑定在页面上,所以需要通过page来获取相关的状态以及触发一些action。但其实页面不需要关心这些状态和action,那么如何将这部分逻辑解耦出来呢?

使用rematch之后的做法是,将这个函数改为一个异步action,迁移到组件的model中去。

const clickSchoolActivityBtn = (rootState, dispatch) => {
    let {
        orderInfo,
    } = rootState;
    
    ......
    
    dispatch.schoolActivityShareLayer.hide();
}


const schoolActivityDetail = {
    state: null,
    reducers: {
        setSchoolActivityDetail(state, playload) {
            return playload;
        },
        clear(state, playload) {
            return null;
        }
    },
    effects: (dispatch) => ({
        async clickSchoolActivityBtn(params, rootState) {
            clickSchoolActivityBtn(rootState, dispatch);
        }
    })
}

异步action中的rootState包含了当前域内的所有状态,而dispatch可以索引到所有action函数,因此可以使用rootState和dispatch来接管原先page的工作,从而完全舍弃page,实现解耦。

3.3 如何实现组件复用

组件内容都抽到一个文件了,那么具体怎么去复用呢?开始我们想的方案是在组件绑定状态的地方更改数据源。例如,加入A、B两个页面,都需要用到该组件,且组件除了数据源不一样以外其余逻辑都相同,如下所示。

const mapState = state => ({
    noticeDetail:state?.pageASource,
})
const mapState = state => ({
    noticeDetail:state?.pageBSource,
})

但这个方案的缺点是,每次在一个新场景使用该组件,都要复制一份入口文件,且需要更改入口文件的数据源,这样一来不仅入口文件代码会重复而且操作也略显麻烦。那么有不需要改动入口文件的方案么?

这时我们想到了rematch的异步action,在异步action中,第一个参数是自定义的,可以传入任意自己所需的数据。因此可以通过异步action来暴露一个函数出来,单独给页面设置数据源。这样一来,对组件来说,就屏蔽了调用方的细节,组件内只需要这个数据类型,而组件外具体是哪个页面使用,数据来源是什么,都不用关心。

const noticeDetail = {
    state: null,
    reducers: {
        setNoticeDetail(state, playload) {
            return playload
        },
        clear(state, playload) {
            return null
        }
    },
    effects: (dispatch) => {
        async setDataSource(params, rootState) {
            let res = await getRecommendForOrder({orderNumber: params.orderNumber});
            if (res) {
                dispatch.noticeDetail.setNoticeDetail(res);
            }
        }
    }
}

在上图这个场景中,我们暴露出了一个setDataSource方法,在页面中使用该组件时,只需引入组件,并在合适的地方给组件设置数据源即可。

dispatch.noticeDetail.setDataSource({'orderNumber': pageA.orderNumber});
dispatch.noticeDetail.setDataSource({'orderNumber': pageB.orderNumber});

这样一来,如果需要在新页面中加入这个组件,只需要在页面方设置数据源即可,组件无需任何改动。

3.4 其它问题

3.4.1 如何及时获取最新状态

在异步action中,如果在通过dispatch改变某个状态后,通过rootState去拿是无法拿到最新状态的,因为其状态改变最终都是通过setState来触发,而这个方法不是同步执行的。如果需要立即拿到最新的状态,可以直接从store中去获取。

import {newStore} from "../../../Store";


let orderInfo = newStore?.getState()?.orderInfo;

3.4.2 预加载组件缓存问题

为了加快二次启动的速度,之前在RN里做了预加载优化。RN在开了预加载的情况下,由于先前的状态仍然保存着,下次再进入该页面会造成页面数据显示不准确问题,所以就需要在页面退出之前,清除掉之前的状态。由于组件之间各自独立, 需要各个组件暴露自己的clear方法,用以清理自身的状态。

const isRefreshing = {
    state: false,
    reducers: {
        setIsRefreshing(state, playload) {
            return playload;
        },
        clear(state, playload) {
            return true;
        }
    }
}

组件自己在销毁的时候需要清除掉自己的状态,如下所示:

useEffect(() => {
    return () => {
        props?.clear();
    }
}, []);

另外页面在销毁的时候也需要清除所有子组件的状态。如下图,通过connect,将各个组件的状态引入,通过将各个组件的clear方法集中来达到清理所有状态的目的。

const mapDispatch = ({component1, component2, component3}) => {
    clear: () => {
        component1.clear();
        component2.clear();
        component3.clear();
    }
}
四、 结果与回顾

目前我们的改造计划已经完成了第一期和第二期,实践下来效果达到了预期。

新页面使用rematch框架开发,写法简便,配合函数式和react hooks,大大节省了代码量。详情页使用rematch框架重构,主页面变得清晰可读,index文件的代码量简化到了原来的32%,且详情页各个组件变得独立可复用。

后续我们也会开展第三期的改造,将rematch框架应用到全流程当中去。

【推荐阅读】

《携程架构实践》

京东

当当

《携程人工智能实践》

京东

当当

 “携程技术”公众号

  分享,交流,成长

基于 YOLOv26 的电路焊点虚焊检测系统:AI 质检实战 本文介绍了一种基于YOLOv26的电路焊点虚焊检测系统,利用深度学习技术实现自动化质检。系统能识别虚焊、桥接、少锡等8种常见焊点缺陷,具有高精度、实时性和强鲁棒性等特点。文章详细阐述了系统架构,包括数据采集、预处理、YOLOv26检测模型和后处理模块,并提供了代码实现的关键部分,如数据预处理增强和模型训练配置。该系统可显著提高电子制造业的质检效率和准确性。 阅读详情

相关推荐

保姆级教程:Java调用海康SDK实现录像回放与倍速播放(附完整代码)

本文详细介绍了如何使用Java调用海康SDK实现录像回放与倍速播放功能,包括开发环境配置、设备连接、流媒体处理、倍速播放实现及性能优化等关键步骤。通过完整的代码示例和实战经验,帮助开发者快速构建智能录像回放系统,提升开发效率。

weixin_29285605的博客 357

H5样本工厂:轻量级深度学习训练样本生产方法论

深度学习训练样本制作是AI落地的关键瓶颈,其本质是将真实场景中的人眼判断高效转化为机器可读的结构化标注数据。传统方式依赖专业工具或人工抠图,成本高、一致性差、难以覆盖产线长尾场景。H5样本工厂以HTML5为交付载体,通过采集控制、实时标注、产线级图像增强与标准化导出四大闭环环节,实现零安装、跨平台、低门槛的样本协同生产。它融合WebRTC、OpenCV.js与WebAssembly等前端重能力,将样本质量约束(如IoU校验、熵值过滤、噪声指纹库)前置到采集端,显著提升模型在真实环境中的泛化能力。适用于工业巡

weixin_34128839的博客 355

OLLAMA_HOST环境变量设置全攻略:从127.0.0.1到局域网共享的完整配置

本文详细解析了OLLAMA_HOST环境变量的核心作用与配置方法,指导用户如何将Ollama服务从仅限本机访问(127.0.0.1)扩展到局域网共享。文章涵盖了macOS、Linux、Windows三大平台的实战配置步骤,并提供了安全加固、性能优化及常见故障排查方案,是解决多设备协作访问本地AI模型的完整指南。

weixin_28455801的博客 1896

干货 | RN框架在携程旅行鸿蒙应用的全业务适配实践

作者简介携程鸿蒙框架技术团队,负责携程旅行鸿蒙系统原生应用开发,为鸿蒙生态用户提供一站式旅行服务。团队热招岗位:资深移动端工程师、高级iOS开发工程师携程作为鸿蒙生态在旅游行业的重要合作伙伴,早在鸿蒙服务卡片时期就和华为开始合作。2023年9月,华为宣布鸿蒙原生应用启动开发,同年12月,我们完成携程旅行鸿蒙Beta版本的开发,技术上基于Web+部分原生的方案实现。24年6月HarmonyOS Ne...

携程技术 3044

利用 AI 自动生成 BDD(行为驱动开发)格式的 Gherkin 测试用例

文章摘要 当前BDD测试领域正经历AI驱动的变革浪潮。传统Gherkin用例编写面临四大痛点:语法负担重、场景发现成本高、一致性差和维护困难。2025-2026年,AI生成Gherkin的工具生态快速成熟,主要分为五类:测试管理平台内置AI(如TestRail 10.2)、Jira插件(如AssertThat BDD)、独立AI平台(如PrimeCompass)、CLI工具和研究原型。其中,TestRail实现生成-执行闭环,AssertThat采用多阶段Agent工作流提升质量,PrimeCompass则

ZXSXJ的博客 205

Xilinx DDR3 MIG IP核设计--汇总导航

快速上手Xilinx DDR3 IP核----汇总篇

孤独的单刀 2万+

React/ReactNative 状态管理终于懂了!redux redux-toolkit 与 rematch 对比总结

有同学反馈开发 ReactNative 应用时状态管理不是很明白,这个问题我之前刚接触 React 时也遇到过,看了好多文章和视频才终于明白,不得不说,React 及三方库这方面做的有点过于复杂了!

张拭心的博客 shixinzhang 1623

跨平台商品模型大解析:亚马逊 vs 阿里 vs 拼多多

本文深入探讨了亚马逊、阿里巴巴和拼多多三大电商平台的商品模型设计,分析了它们在变体关系、商品抽象层级和SKU定义等方面的异同。亚马逊模型以物流和变体为中心,强调全球仓配体系下的标准化管理;阿里模型采用多视角的弹性结构,适用于多类目、多品牌、多卖家环境;拼多多模型则结合平台标准化与商家个性化,适合短期促销和快速上新场景。文章还提供了实践建议,帮助自研电商平台或商品中台的开发者选择合适的商品结构,并强调了商品模型在电商系统中的核心作用。通过对比分析,本文旨在为读者提供商品建模的启发和参考。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 13万+

干货 | 微信小程序一键转百度小程序,携程火车票团队是这样做的

作者简介张海明,携程火车票研发部开发经理。2015年加入携程,从事火车票Android、ReactNative和小程序相关研发工作。一、前言随着微信小程序的逐渐火爆,百度...

携程技术 1259

域适应分类:MCD论文笔记——Maximum Classifier Discrepancy for Unsupervised Domain Adaptation

域适应分类:MCD论文笔记——Maximum Classifier Discrepancy for Unsupervised Domain Adaptation

qq_50001789的博客 1005

PCL 加权局部最优投影(WLOP)简化算法

WLOP算法是一种点云重采样方法,通过迭代优化实现点云均匀化和特征保留。算法包含数据项(加权平均位置保持几何特征)和正则化项(排斥邻近点实现均匀分布)两部分。代码实现基于PCL库,通过KD树加速邻域搜索,使用高斯权重函数计算点位置更新。参数包括输出点比例、邻域半径、正则化权重和迭代次数。该算法不依赖网格信息,适合处理大规模扫描数据的预处理优化。

点云侠的博客 630

推荐一款超高效状态管理工具:Rematch js

在前端开发中,状态管理一直是一项重要任务。Redux以其强大的功能和广泛的应用场景被誉为状态管理的神器,但随之而来的冗余代码也让开发者感到头疼。今天,我们要向您推荐一个简化Redux最佳实践的框架——Rematch js,它在不增加额外负担的情况下,将状态管理变得简单易行。 ## 项目简介 Rematch js是一个轻量级的状态管理库,基于Redux构建,但摒弃了繁琐的配置、action类型、...

gitblog_00572的博客 550

YOLOv8-Pose 姿态识别 RK3588 实战:从模型训练到 RKNN 部署,精度与推理速度双提升

本教程从YOLOv8-pose模型的姿态识别训练,到RK3588的边缘量化部署,为你打造了一套“高精度+高实时性+低成本”的人体姿态分析解决方案。无论是健身动作纠正、智能安防行为检测,还是工业人员姿态监控,这套技术都能直接复用——你只需替换数据集与业务逻辑,即可快速落地专属的边缘AI姿态识别系统。如果你在实践中遇到任何卡点,欢迎随时交流。记住,人体姿态识别的价值在于“关键点准、推理快、部署易”,而这三者的平衡,正是你通过本教程能掌握的核心能力。

FJN110的博客 364

React/ReactNative 状态管理: rematch 如何使用

有同学反馈开发 ReactNative 应用时状态管理不是很明白,接下来几篇文章我们来对比下 React 及 ReactNative 状态管理常用的几种框架的使用和优缺点。

张拭心的博客 shixinzhang 1083

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

React Native for OpenHarmony 实战:Rematch 框架使用指南

⚡零配置启动:内置默认配置减少样板代码📦TypeScript 原生支持:完善的类型推导🔌插件生态系统:支持持久化、日志等扩展fill:#333;important;important;fill:none;color:#333;color:#333;important;fill:none;fill:#333;height:1em;Rematch 在 OpenHarmony 的核心应用模式 ✅跨平台状态管理性能优化策略 📊针对鸿蒙系统的特殊适配方案 📱未来优化方向。

Abin 1109

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

react数据集中式管理第四篇--@rematch/core

今天,我们来介绍@rematch/core 其他几篇: react数据集中式管理第一篇–Redux初认识 react数据集中式管理第二篇–@reduxjs/toolkit react数据集中式管理第三篇–redux-saga @rematch/core的使用教程 Rematch是在redux的基础上再次封装,使用rematch,我们就不需要再声明action类型、action创建函数、thunks配置; 如果你之前学过vuex,那你对这个不会陌生,因为模式基本上一样。 引入依赖: yarn add&nbsp

weixin_43969517的博客 1557

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

前端面试宝典React篇08 列举一种你了解的 React 状态管理框架

一涉及状态管理,内容就相当多了,在面试中也是非常浓厚的一笔。对于本讲梳理的知识导图请务必掌握,最好可以自己画一画;本讲中提到的代码也都要看一看,可以加深对概念的理解。因为大厂中的前端项目结构的复杂性高,一定会使用状态管理框架来规范模块划分与人工操作。所以在面试前,一定要确保能够完全消化本讲中的内容。下一讲开始为你讲解渲染流程的内容,会相对轻松一些。《大前端高薪训练营》

fegus的博客 690

redux探索:rematch

redux存在的问题项目中redux的样板文件太分散,书写和维护都比较麻烦使用thunk来处理异步操作,不是那么直观方案对比基于redux数据流的管理方案:Dva、mirror和rematchDvaDva是蚂蚁金服开源的一个数据流管理方案,基于redux和redux-saga,简化了开发体验。Dva是一揽子的解决方案,可以使用侵入性很强的dva-cli来快速搭建项目,提供了路由层面的适配;也可以使...

weixin_34194551的博客 1012

Rematch是没有样板的Redux最佳实践

Rematch官网 使用Rematch可以使全局状态管理更加的简单和方便 这里只做基本使用介绍,具体可查阅官网 这里的使用是在react hooks组件中 一、安装rematch yarn add @rematch/core 二、rematch使用 新建文件models/count.js export const count = { state: 0, reducers: { // 用纯函数处理状态更改 setCountState(values, payload) {..

why404 1205

rematch的基本用法

rematch是对redux的二次封装,简化了redux是使用,极大的提高了开发体验。rematch仅仅是对redux的封装,没有依赖redux-saga,也没有关联react,因此其可以用在其他的视图库中,如vue等。 1. rematch的优点 1.省略了action types 不必再多次写字符串,使用model/method代替 2.省略了action creators ...

weixin_30919429的博客 1726

rematch简单使用

import {init,dispatch} from 'rematch/core'; const count = { state:{ number:0 }, reducers:{//一个改变该model state的所有函数的对象 increments:(state,payload) => state.number + payload, decrements:(stat...

wangweiruning的博客 2391

Taro + rematch + 云开发实践(一)-初始化项目

引言 最近想尝试小程序云开发又不想为此单独去学习原生小程序,遂做了一波功课,具体可查看凹凸实验室的文章 小程序多端框架全面测评 因本人使用的是React,所以选择了react写法的Taro 本文将教你如何搭建项目 github.com/zhixiaoqian… 个人认为最佳实践主要知识点如下: Taro Taro UI Rematch(redux最佳实践) 小程序云开发(小程序官方...

weixin_34174105的博客 788

rematch:当你受不了redux繁琐写法的时候,是时候了解一波rematch了

前言: 前段时间学习完react后,刚好就接到公司一个react项目的迭代,顺便巩固一下前段时间的学习成果。项目使用的是redux+react-router,将所有的数据都放在redux中,异步处理数据使用redux-saga。由于是迭代项目,所以代码风格还是沿用之前项目的写法,将所有的数据都放在redux中。写redux的时候心中默默的吐槽了无数次,特别是每次从服务端异步获取数据的时...

diewan6825的博客 799

干货 | 响应式设计在携程火车票的应用

作者简介永利,携程开发经理,专注于Web领域的探索。一、什么是响应式设计?可能很多人脑海中已经出现了这样一个动画,当浏览器中页面尺寸不断变化时,内容也在随之变化。简单说,响应式网站设计...

携程技术 449

Redux、rematch、dva的替代品:smox

背景 我们平时在开发 React 项目中,深深的感受到了 Redux 的“长得丑,用得烦”,有的人去改造它,如 dva、rematch,对 Redux 包装语法糖,也有如 smox ,直接重熔再生,完全摆脱 Redux 的局限的同时,还能拥抱“新特性” rematch 作者文章里提到,工具质量 = 工具节省的时间 / 使用工具消耗的时间 我们接下来就用这...

weixin_34392906的博客 637

React Hooks之useReducer

useReducer :接受类型为 (state, action) =&amp;amp;amp;amp;gt; newState 的reducer,并返回与 dispatch 方法配对的当前状态。(如果你熟悉Redux,你已经知道它是如何工作的。) 下面定义两个计数器Counter组件 和 CounterTest组件,使用 useReducer 使它们共享一个count state,当一个组件的 count state发生变化时...

Julia的博客 4583
上一篇: 干货 | 携程是如何做AB实验分流的
下一篇: UED专栏 | 带你认识携程插画系统1.0
携程技术
博客等级 码龄10年 3716粉丝 324原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值