主流都是在推荐 eas 云打包,不仅排队时间长,还总是排了老长的队又很容易出错,有时甚至是云打包所用的机器网络差点意思导致依赖安装失败了。就断掉整个打包流程。然后你就需要重新排队打包。不出意外又要排队两个小时。有点离谱。
eas 也支持--local 参数进行本地打包,但是本地打包还要登录 eas 账号,没一点代码安全感。很离谱。
不仅没安全感,就算你登上了,也会提示你 windows 不支持。离离原上谱。
如果使用 windows subsystem for linux 又会大概率牵扯出不会正确使用 WSL 的各种疑惑。而且 expo 文档上也不会告诉你怎么通过 wsl 打包,因为 expo 团队就没想着兼容 windows 平台,也不会给你测试 wsl 能不能正常用于打包。
有没有安全且方便的 windows 系统的打包 expo 项目的 apk 的方式呢,有的兄弟有的
打开 exe 文件,跟着安装向导下一步下一步...
打开安装好的 Android Studio ,
点击不给谷歌发送使用数据,
提示需要下载 SDK 和安卓模拟器,下一步到 License 界面,会展示 android-sdk 的许可内容,点下面接受的单选按钮
点击左侧 android-sdk-preview-license 查看第二个许可内容,再点下面的接受单选按钮
SDK 和安卓模拟器的下载需要消耗 50 分钟(我的网速是 1.7MB/s)
时间宝贵,你可以先干点别的。
下载好了就重启一次电脑
感觉内存不够用的可以打开虚拟内存(推荐勾选“自动管理所有驱动器的分页文件大小”)。
使用 npm ci 强制使用 package-lock.json 的依赖清单安装依赖
使用 npx expo prebuild 构建出 android 工程目录
打开之后自动执行更新索引和下载项目的依赖包,这一步耗时70 分钟(我用的 4 核 CPU ,网速是 1.7MB/s)
再次提醒,时间宝贵,你可以先干点别的。
点击左上角三个横线,鼠标放到 Build ,再放到二级菜单的 Generate App Bundles or APKs,点击 Generate APKs
这一步同样耗时巨大,需要60 分钟
点击左上角三个横线,鼠标放到 Build ,点击 Generate Signed App Bundle or APK
选择 APK 单选框,下一步要求你使用签名,有的话就选创建好的,没有的话就创建新的
再下一步,在 debug 和 release 之间选择 release ,点蓝色的 create 按钮。大部分依赖都在制作调试基座时缓存过了,所以这次打包大概五分钟后就生成好了
找个存放秘密的好地方,新建文本文件,并改名成后缀为 jks 的文件如 xxx 的签名.jks
在 Android Studio 里面点 create new..., 第一个输入框是填你刚刚创建的 jks 文件路径,可以点击输入框右侧的文件夹图标选取你的 jks 文件。
Validity Years 是签名有效时长多少年,如果过了这个时间需要重新制作签名。因签名文件变化也会导致老版本无法升级成新版本。只能卸载重装为新版。
剩下的输入框如果没什么特别的安全性要求,无脑都写一样的就能用。如果有应用安全的要求就好好写。
引入新的原生模块时需要重新制作调试基座,因为旧的调试基座不包含这部分新的原生代码。
要用的系统权限需要在 app.json 里面提前列出来,并打入调试基座,否则代码里直接请求获取权限会得到 never ask again(拒绝且不再询问)
不涉及主要功能修改,小游戏修改样式,添加接口。大概三个页面,5-6 个接口
预算 500-600 ,预估工时 1 天。
可以联系我获取具体信息,今明两天完成,周末要给到。
小龙号 Base64.encode(000000)
]]>useEffectEvent
的函数,在入门文档里还多次提到。 源码如下 https://github.com/sanity-io/use-effect-event/blob/main/src/useEffectEvent.ts 这个貌似是 ahooks 的 useMemoizedFn 全方位弱化版。
就是说这个使用范围限得很死干不了 useCallback 的活,而 useMemoizedFn 可以完全替代 useCallback 和 useEffectEvent 。
看了眼二者的源码,主要区别是 useEffectEvent 只有在 render 后才有值,所以不能马上用,这和 useCallback 不同。
那问题来了,为什么 react 要出这个垃圾版 useEffectEvent/useCallback 而不是 ahooks 的终级版呢?应该是有我想不到的理由,或者我的理解有什么不对的地方?
]]>useEffect:
useEffect(() => { fetch(`xxx?pageSize=${pageSize}`) }, [pageSize])
在 state 发生变化的组件调用 fetch:
<Pagination pageSize={pageSize} OnChange={(pageSize) => { fetch(`xxx?pageSize=${pageSize}`) }} />
我个人更倾向第二种,第一种 useEffect 看上去更方便,不用第二种需要在每个 state 变化的组件调用 fetch ,但是长期维护下来可能会有意想不到的 bug (公司里有个项目因为缓存的 code 和后端返回的 code 不同,导致 useEffect 调用了两边,自己 dev 环境下 mock 很难察觉)
]]>那我的疑问来了,前端技术集大成者 React 是否属于湿湿的雪和长长的坡。
我们应该怎么的辩证的、长远的、历史的看待 React 和更好的学习 React 。
]]>在快速发展的前端生态中,开发者们一直在寻找既能提高开发效率,又能保证代码质量和用户体验的解决方案。今天,我们很兴奋地向大家介绍 Metis UI —— 一个基于 Tailwind CSS 构建,继承 Ant Design 交互逻辑的现代 React 组件库。
在众多组件库中,Metis UI 独树一帜,它不是简单的重复造轮子,而是在继承优秀设计理念的基础上,带来了全新的开发体验:
Metis UI 基于 Ant Design 久经考验的组件逻辑构建,确保了交互模式的一致性和可靠性。同时,我们抛弃了传统的 CSS-in-JS 方案,全面拥抱 Tailwind CSS ,为开发者带来了前所未有的样式自由度。
import { Button, Input, Form } from 'metis-ui'; // 简洁的 API ,强大的功能 <Button type="primary" className="hover:scale-105 transition-transform" > 自定义样式,轻而易举 </Button>
无需学习复杂的主题配置,直接使用 Tailwind 类名即可实现个性化定制。
interface ButtonProps { type?: 'primary' | 'default' | 'dashed'; size?: 'small' | 'middle' | 'large'; loading?: boolean; ... }
每个组件都提供完整的类型定义,让你的开发过程更加安全和高效。
<Button className="bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700"> 渐变按钮 </Button>
利用 Tailwind 的强大功能,轻松实现复杂的样式效果。
# npm npm install metis-ui # pnpm (推荐) pnpm add metis-ui # yarn yarn add metis-ui
向你的入口 CSS 文件添加一个 @plugin
以导入 Metis UI 。
@import 'tailwindcss'; @source './node_modules/metis-ui/es'; @plugin 'metis-ui/plugin';
import { Alert } from 'metis-ui'; const App = () => ( <div className="h-screen w-screen"> <Alert type="info" banner message="Hello" description="Welcome to metis-ui" /> </div> ); export default App;
Metis UI 只针对颜色进行主题定制,默认提供了两套主题:light
和 dark
。您还可以创建自己的自定义主题或修改内置主题。
您可以在 CSS 文件中的 @plugin "metis-ui/plugin"
后添加括号来管理主题,详细介绍。
我们提供了一套开箱即用的企业中后台系统模板,基于 React、react-router、TypeScript、Vite、TailwindCSS、Zustand、faker-js、MSW 等技术栈构建。它内置了开箱即用的数据流、国际化、菜单、模拟数据、权限管理、主题切换等功能,助力企业快速搭建高质量的中后台应用。
├── .husky # Husky 钩子配置目录 ├── public # 公共静态资源目录 ├── src # 源码目录 │ ├── apis # 服务端接口请求相关 │ ├── assets # 静态资源(图片、SVG 等) │ ├── components # 通用组件 │ ├── hooks # 自定义 hooks │ ├── layouts # 页面布局组件 │ ├── locale # 国际化资源 │ ├── mocks # Mock 数据与服务 │ ├── pages # 页面组件 │ ├── store # Zustand 状态管理 │ ├── types # TypeScript 类型定义 │ ├── utils # 工具函数与工具类 │ ├── loading.tsx # 全局 Loading 组件 │ ├── main.tsx # 应用入口文件 │ ├── routes.tsx # 路由和菜单配置 │ └── vite-env.d.ts # Vite 环境类型声明 ├── .env # 环境变量配置文件 ├── .lintstagedrc # lint-staged 配置文件 ├── .prettierignore # Prettier 忽略文件配置 ├── .prettierrc # Prettier 代码格式化配置 ├── commitlint.config.js # 提交规范校验配置 ├── eslint.config.js # ESLint 代码规范配置 ├── index.html # 项目入口 HTML ├── package.json # 项目依赖与脚本配置 ├── tailwind.css # TailwindCSS 全局样式入口 ├── tsconfig.app.json # TS 应用配置 ├── tsconfig.json # TS 根配置 ├── tsconfig.node.json # TS Node 配
]]>tips: 网站匀部属在 Github Pages, 访问可能需要梯子
Gluestack 上至少有 17 个已经被感染的软件包,这些软件包的周下载量高达 100 万次,即,典型的供应链攻击。
消息来源: https://www.landiannews.com/archives/109286.html https://www.aikido.dev/blog/supply-chain-attack-on-react-native-aria-ecosystem
]]>我认为在博文只有 100 条左右的时候,/api/posts
应该没有明显差距(尤其是 posts 接口还不获取内容,只获取标题、简介、发布日期之类的东西)
我假设都需要 200ms.
那么按 gpt 的意思来干的话,页面会是
|-- 白屏
|--|-- 200ms 后接口获取到数据,渲染 html 输出到前端
|--|-- 同时 Suspense 显示 fallback
|--|-- 同时请求第二个 get 接口,
|--|--|-- 再 200ms 后接口获取到数据,渲染 html 输出到前端
按我的意思的话,页面会是
|-- Suspense 立即显示 fallback
|-- 同时请求 get 接口,
|--|-- 200ms 后接口获取到数据,渲染 html 输出到前端
这不是明显我的方案更优吗,省了 200ms 的白屏。可 gpt 非说它的更好。
大佬们帮我看看,是不是我理解得不到位。
'use server' async function Posts({ start, count }: { start: number; count?: number }) { const data = await get('/api/posts', { start, // 假设 count 为空的时候获取后续所有 count, }) return <RenderPosts data={data} /> } // gpt 的意思是这样 export function Page() { return <> <Posts start={0} count={10} /> <Suspense fallback={<div>loading</div>}> <Posts start={10} /> </Suspense> </> } // 我的意思是这样 export function Page() { return <> <Suspense fallback={<div>loading</div>}> <Posts start={0} /> </Suspense> </> }
]]>product.purchase(productId)
会返回购买成功 success ,但Transaction.currentEntitlements
又取不到生效的订单,我以为是有没过期还在续订的订单。 但用Transaction.all
查到所有订单之后发现所有订单都是过期的。完全没头脑,官方文档也翻了几遍,AI 也问了各种,就是不知道为啥。
求个老哥帮忙解决下,可付费。
另外之所以用桥接没有直接用 react-native-iap ,是因为上周遇到一个蜜汁问题,死活查不到在 apple store connect 配置的 sku ,后面按照 github 其他人的教程用了桥接调用就 OK 了。
这是 purchase 的代码:
func purchaseProduct(_ productId: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { Task { do { let products = try await Product.products(for: [productId as String]) guard let product = products.first else { reject("no_product", "未找到对应产品", nil) return } let result = try await product.purchase() print("[StoreKit2Module] 购买结果: \(result)") switch result { case .success(_): print("[StoreKit2Module] 购买成功") resolve("购买成功") case .userCancelled: print("[StoreKit2Module] 用户取消了购买") reject("cancelled", "用户取消了购买", nil) case .pending: print("[StoreKit2Module] 购买处于等待状态") reject("pending", "购买处于等待状态", nil) @unknown default: print("[StoreKit2Module] 未知的购买结果") reject("unknown", "未知的购买结果", nil) } } catch { print("[StoreKit2Module] 购买时发生错误: \(error)") reject("purchase_error", "购买时发生错误: \(error)", error) } } }
]]>在 React Native 开发中,图片加载和渲染性能一直是一个常见的痛点,尤其是在处理大量图片或需要高性能的场景时。react-native-fast-image 大概快三年没有维护了。react-native-turbo-image 就是为了解决这个问题而诞生的。
极速加载:原生优化,图片加载速度大幅提升。
内存优化:智能缓存和内存管理,减少 OOM (内存溢出)风险。
高度可定制:支持自定义加载策略、缓存控制和图片处理。
第一次用 react ,就用 AI 做了,发现 SEO 不好,搜索引擎不好收录,但是都做完了。。现在该 咋办哦。。
]]>假如前端有如下页面组件 a 和 b ,a 和 b 中有一部分并集的功能,比如 card 的边框,标题什么的
我一般会拆成 BaseCard ,ACard ,BCard 三个组件来写,包括 ts 也是,interface BaseCardProps ,然后被另外两个组件继承。我自认为写到还算优雅,组件分拆出来每个文件代码量一般控制在 100 行内,顶多 300 行出一点。
行数超 300 的话,后续有时间整理代码我一般会按不同功能细化继续拆分出组件。看到有人说 javaer 写点简单功能就先写十几个文件然后到处继承,每个类代码很少,难道我一直以来坚持的写法是错误的吗,all-in-one 全堆一起才是正确写法?
]]>这个项目 docker 部署,修改.js 文件按,但是页面没有发生改变,清除缓存了,ai 也问过了。
]]>最近在学习 react 和 nextjs ,算初学者,感觉我写的很多 useEffect eslint 都提示缺少依赖,但其实我觉得写的依赖已经够了
比如这样
const [conversation, setConversation] = useState<Conversation[]>([]) useEffect(() => { if (currentChatTitle) { setConversation( conversation.map((i) => { return { ...i, title: i.id === currentChatId ? currentChatTitle : i.title, } }) ) } }, [currentChatId, currentChatTitle])
eslint 就说缺少conversation
这个依赖,但是加了之后就无限执行这个 useEffect 回调了,其实我连这个currentChatId
都不想加入依赖
eslint 也给了解决方案就是改成setXXX((prev)=>xxx)
,但这样好麻烦啊,或者就是 disable 掉这一行
useEffect(() => { if (currentChatTitle) { // 改成`setXXX((prev)=>xxx)` setConversation((conversation) => conversation.map((i) => { return { ...i, title: i.id === currentChatId ? currentChatTitle : i.title, } }) ) } }, [currentChatId, currentChatTitle])
请问下各位平时会关掉这个eslintreact-hooks/exhaustive-deps
这个规则吗
function ToggleButtonRemastered({ isEnabled, children }) { return ( <button className={clsx( isEnabled && "scale-110", "transition-transform duration-200 w-max text-xl" )} > {children} </button> ) }
和
function ToggleButtonClassicEdition({ isEnabled, children }) { return ( <button data-enabled={isEnabled} className="data-[enabled=truel:scale-110 transition-transform duration-200 w-max text-xl" > {children} </button> ) }
]]>在 MyShell ,我们坚决贯彻开源路线。我们的模型—OpenVoice (语音克隆)、MeloTTS (文本转语音)和 JetMOE (大型语言模型)在 Hugging Face 上已被下载超过 200 万次,在 Github 上获得了超过 33K 的星标。我们还开源了自研的 Agentic 框架 ShellAgent ,辅助开发者端到端构建自己的 Al 应用。我们的团队由来自麻省理工学院、普林斯顿大学和牛津大学等顶尖学府的才华横溢的人才组成,致力于在有冲劲和公开透明的工作环境中促进创新。
公司产品: https://app.myshell.ai/explore ,iOS App 在海外 App Store 搜索 myshell 即可体验
前端开发工程师 岗位职责:
任职要求:
加分项:
简历投递方式: eric@myshell.ai 或➕v MTU4MTEwNTMzMDg=
]]>要求不高,大体符合即可。
]]>最近自娱自乐时,写了一个类似高中物理的木板-滑块组件,可以根据木板的角度来控制小球的位置,见图: https://imgur.com/a/Eo2briC
组件有个问题,在旋转到 90 度附近时,值会突然从 0 跳到 100: https://imgur.com/a/kWmm3I4
我知道问题出在 handleMouseMove
函数里,斜率 k 在 90 度附近发生了跳变,但不会解决,求教
我看源码就是先 UnmountEffects 后 MountEffects,里面也只是递归遍历而已,为什么 cleanup 里面的 props 是上一次的了?
commitPassiveUnmountEffects(root.current); commitPassiveMountEffects(root, root.current, lanes, transitions);
// 复现的 demo function App() { const [num, setNum] = useState(100) window.__setNum = setNum return <Comp num={num}></Comp> } function Comp(props) { debugger useEffect(() => { debugger props // {num:1000} return () => { debugger // 为什么这里是旧的 props? {num:100} props } }, [props.num]) return ( <p> <span>{props.num}</span> </p> ) } setTimeout(() => { __setNum(1000) }, 1000)
]]>另外 autoBatching 对大型项目的性能增益不知道能有多少,比如飞书这种典型大型 React 卡逼 app 如果升到 19 会不会流畅点
]]>印象里 Suspense 和 Transition 这两个功能是 React 18 发布的。似乎 NextJS 之后,React 社区的焦点就变成了 SSR 和 RSC 。这两个功能一直没什么存在感,生态也很一般。
甚至直到现在,官方也没有说明第三方库该如何支持 Suspense:
The requirements for implementing a Suspense-enabled data source are unstable and undocumented. An official API for integrating data sources with Suspense will be released in a future version of React.
说实话这两个功能发布之后,我是一次也没用过。想问问大家用过这个两个 API 吗?体验如何?在新项目中是否会用这些 API ?
]]>1 、如果继续使用 RN 开发,没有合适的组件库时,应该学 Objective-C ,还是 Swift ?
2 、推荐一个学习成本较低的框架( uniapp 就算了~~)
]]>