首页
Search
1
解决visual studio code (vscode)安装时没有选择安装路径问题
138 阅读
2
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
131 阅读
3
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
107 阅读
4
如何在 Clash for Windows 上配置服务
77 阅读
5
Uniapp如何引入自定义样式文件
75 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,061
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
624
篇与
的结果
2024-08-24
React Native 搭配 MobX 使用心得
MobX 是一款十分优秀的状态管理库,不但书写简洁还非常高效。当然这是我在使用之后才体会到的,当初试水上车的主要原因是响应式,考虑到可能会更符合 Vue 过来的思考方式。然而其实两者除了响应式以外并没有什么相似之处:joy:。在使用过程中走了不少弯路,一部分是因为当时扫两眼文档就动手,对 MobX 机制理解得不够;其它原因是 MobX 终究只是一个库,会受限于 React 机制,以及与其它非 MobX 管理组件的兼容问题。当中很多情况在文档已经给出了说明(这里和这里),我根据自己遇到的再做一番总结。与非响应式组件兼容问题与非响应式的组件一起工作时,MobX 有时需要为它们提供一份非响应式的数据副本,以免 observable 被其它组件修改。observable.ref使用 React Navigation 导航时,如果要交由 MobX 管理,则需要手动配置导航状态栈,此时用 @observable.ref “浅观察”可避免状态被 React Navigation 修改时触发 MobX 警告。当 Navigator 接受 navigation props 时代表导航状态为手动管理。import { addNavigationHelpers, StackNavigator } from 'react-navigation' import { observable, action } from 'mobx' import { Provider, observer } from 'mobx-react' import AppComp from './AppComp' const AppNavigator = StackNavigator({ App: { screen: AppComp }, // ... }, { initialRouteName: 'App', headerMode: 'none' }) @observer export default class AppNavigation extends Component { @observable.ref navigationState = { index: 0, routes: [ { key: 'App', routeName: 'App' } ], } @action.bound dispatchNavigation = (action, stackNavState = true) => { const previousNavState = stackNavState ? this.navigationState : null this.navigationState = this.AppNavigator.router.getStateForAction(action, previousNavState) return this.navigationState } render () { return ( ) } }observable.shallowArray() 与 observable.shallowMap()MobX 还提供其它方便的数据结构来存放非响应式数据。比如使用 SectionList 的时候,我们要为其提供数据用于生成列表,由于 Native 官方的实现跟 MobX 不兼容,这个数据不能是响应式的,不然 MobX 会报一堆警告。MobX 有个 mobx.toJS() 方法可以导出非响应式副本;如果结构不相同还可以使用 @computed 自动生成符合的数据。但这两个方法每次添加项目都要全部遍历一遍,可能会存在性能问题。这时其实可以维护一个 observable.shallowArray,里面只放 key 数据,只用于生成列表(像骨架一样)。传给 SectionList 的 sections props 时 slice 数组复制副本(shallowArray 里的数据非响应式,所以只需浅复制,复杂度远小于上面两种方式)。然后 store 维护一个 observable.map 来存放每个项的数据,在项(item)组件中 inject store 进去,再利用 key 从 map 中获取数据来填充。通过 shallowArray 可以让 MobX 识别列表长度变化自动更新列表,利用 map 维护项数据可以使每个项保持响应式却互不影响,对长列表优化效果很明显。// store comp class MyStore { @observable sections = observable.shallowArray() @observable itemData = observable.map() @action.bound appendSection (section) { const data = [] section.items.forEach(action(item => { this.itemData.set(item.id, item) data.push({key: item.id}) })) this.sections.push({ key: section.id, data }) } }// MyList comp import { SectionList } from 'react-native' @inject('myStore') @observer class MyList extends React.Component { _renderItem = ({item}) => render () { return ( ) } }// SectionItem comp @inject('myStore') @observer class SectionItem extends React.Component { render () { const {myStore, id} = this.props const itemData = myStore.itemData.get(id) return ( {itemData.title} ) } }computed利用 @computed 缓存数据可以做一些优化。比如有一个响应式的数组 arr,一个组件要根据 arr 是否为空更新。如果直接访问 arr.length,那么只要数组长度发生变化,这个组件都要 render 一遍。此时利用 computed 生成,组件只需要判断 isArrEmpty 就可以减少不必要的更新:@computed get isArrEmpty () { return this.arr.length
2024年08月24日
5 阅读
0 评论
0 点赞
2024-08-24
获取选择文本所在的段落和句子
最近收到一个 issue 期望能在划词的时候同时保存单词的上下文和来源网址。这个功能其实很久之前就想过,但感觉不好实现一直拖延没做。真做完发现其实并不复杂,但有些小坑。完整代码已作为单独项目发布 get-selection-more,对原理感兴趣欢迎继续往下阅读。获取选择文本通过 window.getSelection() 即可获得一个 Selection 对象,再利用 .toString() 即可获得选择的文本。火狐坑在 Firefox 中,input 和 textarea 里的选词是不能通过 window.getSelection 获取的,只能通过 document.activeElement。锚节点与焦节点在 Selection 对象中还保存了两个重要信息,anchorNode 和 focusNode,分别代表选择产生那一刻的节点和选择结束时的节点,而 anchorOffset 和 focusOffset 则保存了选择在这两个节点里的偏移值。这时你可能马上就想到第一个方案:这不就好办了么,有了首尾节点和偏移,就可以获取句子的头部和尾部,再把选择文本作为中间,整个句子不就出来了么。当然不会这么简单哈😜。跨元素坑一般情况下,anchorNode 和 focusNode 都是 Text 节点(而且因为这里处理的是文本,所以其它情况也会直接忽略),可以考虑这种情况:Saladict is awesome!如果选择的是“awesome”,那么 anchorNode 和 focusNode 都是 is awesome!,所以取不到前面的 “Saladict”。另外还有嵌套的情况,也是同样的问题。Saladict is awesome!所以我们还需要遍历兄弟和父节点来获取完整的句子。反向选坑通过开始和结束节点来计算有个非常棘手的问题,如果用户是反方向选的词,那么开始节点会在结束节点的后方,我们需要反过来拼接。但如何知道是反方向呢?我们只能通过偏移值以及计算元素位置来判断,这就有点麻烦了。可以看到,通过开始结束节点不好计算,我们再看看有什么可用的属性。Range注意到 Selection 对象中还有一个 getRangeAt 方法。这个方法可以获取一个 Range 对象。Range 装的是文档片段,可以包含文本节点中的一部分。我们通过 Range.startContainer 和 Range.endContainer 可以获得 range 开始和结束的节点,通过 Range.startOffset 和 Range.endOffset 获得 range 在节点的偏移值。这里的前后节点不会受用户选词方向影响,所以我们无需再做判断。获取段落拿到选词范围后我们还是得遍历找到前后的段落。于是接下便是解决遍历边界的问题了。遍历到什么地方为止呢?我的判断标准是:跳过 inline-level 元素,遇到 block-level 元素为止。而判断一个元素是 inline-level 还是 block-level 最准确的方式应该是用 window.getComputedStyle()。但我认为这么做太重了,也不需要严格的准确性,所以用了常见的 inline 标签来判断。function isInlineNode(node?: Node | null): node is Node { if (!node) { return false } switch (node.nodeType) { case Node.TEXT_NODE: case Node.COMMENT_NODE: case Node.CDATA_SECTION_NODE: return true case Node.ELEMENT_NODE: { switch ((node as HTMLElement).tagName) { case 'A': case 'ABBR': case 'B': case 'BDI': case 'BDO': case 'BR': case 'CITE': case 'CODE': case 'DATA': case 'DFN': case 'EM': case 'I': case 'KBD': case 'MARK': case 'Q': case 'RP': case 'RT': case 'RTC': case 'RUBY': case 'S': case 'SAMP': case 'SMALL': case 'SPAN': case 'STRONG': case 'SUB': case 'SUP': case 'TIME': case 'U': case 'VAR': case 'WBR': return true } } } return false }获得句子获得选词所在句子我们需要在获取选词前后段落合并前通过正则匹配出句子在选词的前后部分。点号坑我们通过标点符号来判断一个句子结束的位置。这里需要注意 a.b 在编程的文章中十分常见,所以我们在这里不看作是句子的结束。// match head a.b is ok chars that ends a sentence const sentenceHeadTester = /((\.(?![ .]))|[^.?!。?!…\r\n])+$/ // match tail for "..." const tailMatch = /^((\.(?![\s.?!。?!…]))|[^.?!。?!…])*([.?!。?!…]){0,3}/回溯坑如果通过正则匹配前半部分,这里有个严重的性能问题。因为正则只能左往右匹配,随着段落前半部分的长度增加,匹配不成功回溯的复杂度也在增加。遇上非常长的段落(如一些滥用标签的网站)性能损耗甚至肉眼可见。故我们只好手动从右往左遍历一个个地匹配:function extractSentenceHead(leadingText: string): string { // split regexp to prevent backtracking if (leadingText) { const puncTester = /[.?!。?!…]/ /** meaningful char after dot "." */ const charTester = /[^\s.?!。?!…]/ for (let i = leadingText.length - 1; i >= 0; i--) { const c = leadingText[i] if (puncTester.test(c)) { if (c === '.' && charTester.test(leadingText[i + 1])) { // a.b is allowed continue } return leadingText.slice(i + 1) } } } return leadingText }最后获取前后部分之后只需简单拼接即可得到完整的上下文。可以看到当中还是有不少小坑,所以不建议再造轮子, get-selection-more 经过 Chrome 和 Firefox 测试,相对更靠谱些。
2024年08月24日
6 阅读
0 评论
0 点赞
2024-08-24
Web 可访问性整理
定义 可访问性 Accessibility为障碍用户提供同等用户体验。使障碍用户能对产品感知、理解、定位和交互,并能平等地参与贡献。 可用性 Usability可用性和用户体验设计(User Experience Design)是为了让目标用户使用产品高效、满意地达到特定目标。 包容性 Inclusion包容性设计(Inclusive Design)、通用设计(Universal Design)和人性化设计(Design For All)尽可能让每个人都能容易地用上产品。包容性要解决的问题非常广,包括软、硬件的可访问性和质量、互联网连通性、计算机文化和技能、经济状况、教育、地理位置、语言、以及年龄和残障。 体验屏幕阅读要解决问题首先得知道问题是怎样的,体验屏幕阅读器: ChromeVox ,Chrome 扩展 NVDA ,开源跨平台 VoiceOver (MacOS) 工具 校验 Chrome 自带 Audits aXe 扩展、命令行工具等。 webaim.org 调试 Chrome 自带实验性 Accessibility Inspector chrome://flags/#enable-devtools-experiments Web Developer 扩展 Accessibility Developer Tools 扩展 颜色 Color-Oracle 模拟色盲,开源跨平台 Lea Verous Contrast Ratio WCAG Color Contrast Analyzer 参考规范有什么问题查规范准没错。在自行实现支持 ARIA 的元素时很有用。 Web Content Accessibility Guidelines (WCAG) 2.0 Accessible Rich Internet Applications (WAI-ARIA) HTML 5.1 2nd Edition 其它资料文章 Accessibility, Usability, and Inclusion: Related Aspects of a Web for All Accessibility - W3C Web Fundamentals - Accessibility Common idioms without dedicated elements 本文原文 Web 可访问性整理 视频 Google 的 A11ycasts Accessibility by Thomas Bradley Pragmatic Accessibility: A How-To Guide for Teams (Google I/O '17) 课程 官方教程 Web Accessibility Tutorials Web Accessibility Tab对于纯键盘使用者来说, Tab 键承担了重要责任。Tab 顺序要点: Tab 顺序是按照 DOM 结构,而不是 CSSOM 结构。所以通过 CSS 将元素提前(如 flex order)并不会影响 tab 顺序。在排版的时候需要考虑。其它元素Tab 默认只会识别部分元素,如果需要让其它元素也被识别,加上 tabindex="0" 属性。不鼓励使用大于 0 的其它数字,除了会造成混乱,一些屏幕阅读器也不一定会遵循。应该用 DOM 顺序来体现 tab 顺序。忽略 Tab要让 tab 忽略一个元素,即直接跳过去,设置 tabindex="-1" 属性。或者用还在草稿阶段的 inert 属性 (polyfill)。侧导航栏问题在一些响应式的网页,侧导航栏在宽度变小时可能会隐藏起来,这时用户如果使用 tab 跳转可能会发现焦点突然不见了,怎么按也没反应。其实是因为 tab 跳到导航栏的链接去了。解决方式要么改变 DOM 结构,将导航栏移到最后;要么使用前面提到的 inert 属性。Skip Link将导航的每个项目绝对定位到屏幕之上,再设置 :focus 样式移下来。就可以实现用户按 tab 时一次只显示一个导航链接,用户再按回车即可跳到该位置。可以参考 Github 网页。原生元素尽可能使用原生支持的元素,如 ,而不是用 或 模拟。原因: 原生符合语义。 原生对屏幕阅读友好,否则需要写一堆 ARIA 属性来提示阅读器。 原生不需要 JS 支持。 原生元素用键盘可以代替鼠标点击,否则还要监听键盘事件。 Focus Ring 浏览器自动识别原生元素,否则要另外写 CSS 隐藏。 CSS 很容易就能改变原生元素的样式,与整体设计统一。 语义标签使用符合语义的标签,辅助设备会自动理解。 :完整、独立的内容。 每篇 应该包含一个标题(-)。 嵌套的 主题应该跟父 相关联。 考虑使用 应该看其内容是否会出现在文档的提纲(outline)中。 辅助设备会将其 role 理解为“article”。 :按主题归在一起的部分内容。 每块 应该包含一个标题(-)。 如果内容是完整、独立的,应该考虑使用 。 不要将 当 使用,只为样式时应该用 。 考虑使用 应该看其内容是否会出现在文档的提纲(outline)中。 辅助设备会将其 role 理解为“region”,见下方。 :包含一系列链接可以跳转到其它页面或者本页面的某部分。 使用列表元素帮助辅助设备理解。 只为主要导航使用。 辅助设备会将其 role 理解为“navigation”,见下方。 :侧边栏,其内容应该不属于主体内容的一部分。 可以放导航组、广告等。 辅助设备会将其 role 理解为“complementary”,见下方。 -:一个块或子块的标题。 请勿为了样式而用标题来表示副标题、子标题、额外标题、标语等,变通可参考这里。 辅助设备会将其 role 理解为“heading”加上“1”到“6”。 :对最近的父 sectioning content 或 sectioning root 的介绍。 如果父 sectioning root 是 ,辅助设备会将其 role 理解为“banner”,见下方。 :代表其最近的父 sectioning content 或 sectioning root 的页脚。 如果父 sectioning root 是 ,辅助设备会将其 role 理解为“content information”,见下方。 :为其最近的父 或 元素提供联系信息。 只提供必要的联系信息,不要包含其它信息。 sectioning root 包括 , , , , , .Sectioning content 包括 , , , .LandmarksLandmark roles 定义网页的几个主要部分,可以让辅助设备快速跳转。总共有八个。 banner:唯一。跟网站相关的内容,如 logo 、赞助商、站内搜索等。 complementary:对主体内容的补充。与主体内容相关,但本身独立。如相关文章。 contentinfo:唯一。版权信息、隐私声明等。 form:表单。应该设置可见的标题,并用 aria-labelledby 引用标题来告知辅助设备这个表单是干什么的。如果用 JS 提交表单,没有触发 onsubmit 事件,则应该用其它方式通知表单提交。 main:唯一。主体内容。 navigation:导航栏。 region:认为用户可能会感兴趣的,需要让用户可以快速跳转的内容。辅助设备会收集它来生成一个概要页面。每个 region 必须有可见的标题,并用 aria-labelledby 引用。 search:搜索框。 视觉隐藏使用视觉隐藏而不是 display: none; 来隐藏元素同时让辅助设备识别。.visually-hidden { position: absolute; overflow: hidden; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; clip: rect(0 0 0 0); }【完】
2024年08月24日
4 阅读
0 评论
0 点赞
2024-08-24
理解 RxJS :四次元编程
学习 RxJS 最大的问题是官方造了很多概念,但文档又解释得不太全面和易懂,需要结合阅读各种文章(特别是 Ben Lesh 的,包括视频)。本文试图整体梳理一遍再用另外的角度来介绍,希望能帮助初学者或者对 RxJS 的一些概念比较含糊的使用者。为什么需要 RxJSRxJS 属于响应式编程,其思想是将时间看作数组,随着时间发生的事件被看作是数组的项,然后以操作数组的方式变换事件。其强大的地方在于站在四维的角度看问题,这就像是拥有了上帝视野。在处理事件之间的关系时,对于传统方式,我们需要设置各种状态变量来记录这些关系,比如对点击 Shift 键进行计数,需要手动设置一个 let shiftPressCount: number,如果需要每 600ms 清零,又需要添加计时的状态,这些状态都需要手动维护,当它们变得复杂和庞大的时候我们很快就会乱了,因为没有明确的方向,不好判断这些状态同步了没有。而这正是 RxJS 发光发热的地方。因为从四维的角度看,这些状态就不是单个变量,而是一系列变量。比如对按键计数:Rx.Observable.fromEvent(document, 'keydown') .filter(({ key }) => key === 'Shift') .scan(count => count + 1, 0) .subscribe(count => console.log(`按了${count}遍 Shift 键`))相信有使用过数组方法的人第一次看也大概能知道这里干了些什么(把 scan 看作是会输出中间结果的 reduce)。中间状态都在变换的过程中被封装起来,每一次事件的 count 都是独立的,不容易乱,也使得可以用纯函数去表达状态的变换。链式调用(或者 RxJS5 的 pipeable)在一定程度上限制了状态数据的流动方向,增加了可预测性,更加容易理解。理解 RxJS基本概念使用 RxJS 前先理解它要做什么,这里引入了两个概念,Producer (生产者)和 Observer (观察者)。先看一个熟悉的例子:document.addEventListener('click', function handler (e) { console.log(e.clientX) })这里的 Producer 是 DOM 事件机制,会不定期产出 MouseEvent 事件。Observer 就是 handler,对事件作出反应。再看前面的例子:Rx.Observable.fromEvent(document, 'keydown') .filter(({ key }) => key === 'Shift') .scan(count => count + 1, 0) .subscribe(count => console.log(`按了${count}遍 Shift 键`))Producer 还是 DOM 事件机制,Observer 是 subscribe 的参数。所以可以理解 RxJS 为连接 Producer 和 Observer 的纽带。于是这个纽带的成分叫 Observable (可被观察的)就不难理解了。Observable 就是由事件组成的四维数组。RxJS 将 Producer 转换为 Observable,然后对 Observable 进行各种变换,最后再交给 Observer。对 Observable 进行变换的操作符叫做 Operator,比如上面的 filter 和 'scan',它们输入 Observable 再输出新的 Observable。RxJS 有巨量的 Operators ,这也是学习 RxJS 的第二难点,我已经分类整理了六十多个,整理完会再写一篇文章介绍,敬请关注。创建 ObservableRxJS 封装了许多有用的方法来将 Producer 转换为 Observable,比如 fromEvent、fromPromise,但其根本是一个叫 create 的方法。var observable = Rx.Observable.create(observer => { observer.next(0) observer.next(1) observer.next(2) setTimeout(() => { observer.next(3) observer.complete() }, 1000) })这其实跟 Promise 的思路很像,Promise 只能 resolve 一遍,但这里可以 observer.next 很多个值(事件),最后还能 complete(不是必须的,可以有无限事件)。官方把这个类 resolve 的参数也叫做 observer,因为 observer.next(0) 的意思是“Subscribe 我的那个 Observer 接下来会获得这个值 0”。我认为这是一个不好的决定,重名对于新人太容易混淆了,这个其实可以从另一个角度看,把它叫做 producer,“产生”了下个值。Subscribe 不是订阅者模式一个常见的误解是认为 RxJS 就是 addEventListener 那样的订阅者模式,subscribe 这个方法名也很有误导性。然而两者并不是一回事,订阅者模式会维护一个订阅者列表,事件来了就一一调用列表上的每个订阅者传递通知。但 RxJS 并没有这么一个列表,它就是一个函数,可以跟 Promise 类比,Promise 的 executor 是在 new Promise(executor) 时马上执行的,而 RxJS Rx.Observable.create(observer) 的 observer 则是在每次执行 subscribe 后都调用一遍,即每次 subscribe 的 Observables 都是独立的,都会重新走一遍整个流程。这个时候你也许会想,这样每次都完整调用一遍岂不是很浪费性能?没错,如果需要多次 subscribe 同个 Producer 这么做会比较浪费,但如果只是 subscribe 一遍,维护一个订阅者列表也没有必要。所以 RxJS 引入了 Hot 和 Cold Observable 的概念。Hot & ColdObservable 冷热概念其实就是看 Producer 的创建受不受 RxJS 控制。前面我们知道,create 会将 Producer 转化为 Observable 。如果这个 Producer 也是在 create 回调里面产生的,那么就是 Cold ,因为 Producer 还不存在,只有 subscribe 了之后才会被创建。但如果 Producer 在之前就创建了,比如 DOM 事件,create 回调里仅仅是对 Producer 添加 listener,那么这就叫做 Hot ,因为不需要 subscribe 来启动 Producer 。只有 Hot Observable 才可以实现订阅者模式。可以通过一个特殊的 Observable 叫 Subject 来创建,其内部会维护一个订阅者列表。通过 share 方法可以将一个 Cold 的 Observable 转换为 Hot 。原理是内部用 Subject subscribe 上流的 Observable 实现转接。使用 RxJS理解了基本概念之后就可以直接开写了,本身没有什么魔法,参考一下 api 依样画葫芦即可。使用 RxJS 最常见的问题是不知道什么时候该用哪个 Operator 。这其实跟数组操作是一样的,RxJS 提供了数量庞大的 Operators ,基本覆盖了各种可以想到的数组操作,建议先从 JavaScript 常见的数组操作开始,如 map、filter、scan(也有 reduce ,但这个通常不是我们想要的,我们一般不需要在 complete 之后才输出结果,而是每次都输出阶段性的结果)。多翻官方文档,常用的 Operators 都描述得非常详细,有弹珠图(Marble Graph)和一句话总结;缺点是措辞有时可能会比较抽象,不是那么好理解。另外就是第三方的 learnrxjs 和 Rxjs 5 ultimate,按作者的思路组织,更通俗易懂些,可以作为补充理解;缺点是可能跟官方不同步,以及不全。我整理完也会再写一篇文章介绍,敬请期待。
2024年08月24日
5 阅读
0 评论
0 点赞
2024-08-24
深入 React Render Props 模式
随着 React 的新 Context API 出来,render props 模式再次发挥重要作用。本文将尝试深入理解 render props 的利弊,并结合高阶组件寻找合适的处理方式。基础先看官方给出的简单例子: ( Hello{data.target} )}/>加个 DataProvider 的简单实现,class DataProvider extends React.Component { state = { target: '' } handleMouseMove = e => this.setState({ target: e.target.title }) render() { return ( {this.props.render(this.state)} ) } }这里是将一个返回 React 元素的函数传给 DataProvider 的 props.render,DataProvider render 的时候调用 this.props.render(this.state) 渲染这个函数。这也是“render props”名字的来源,而现在更流行的是“children props”,虽然依然沿用 render props 的说法。Children props 即将 render 换为 children ,同时 JSX 中不需要显式写 chidlren ,所以成了这个样子:{data => Hello{data.target}}子组件通过 render props 传进父组件渲染,让父组件不再依赖子组件,达到重用父组件的目的,即依赖反转。Render Props 与 SFC前面提到的“返回 React 元素的函数”,一看是不是跟无状态函数组件(Stateless Fuctional Component)的签名很接近。这么看:{props => Hello{props.target}}但不一样的地方在于 render props 只是一个普通函数,是直接函数调用。且 inline render props 可以跳过 DataProvider 直接访问其它父组件:const App = props => ( {data => Hello{data.target}{props.target}} )这就造成了 DataProvider 不能优化为纯组件。这也是非常不好的习惯,一个解决方式是人为限制 render props 为 SFC 从而让只有一个数据来源。理想很美好,但没法强制所有人这么干。Render Props 与 HOC如果将 render props 限制为传入子组件,其实很容易联想到高阶组件(Higher-Order Components)。高阶组件是一个函数,接受一个组件,返回新的组件。所以可以用高阶组件包装起来,并隐藏 render props 接口。const withData = Base => () => {Base} const BaseTarget = props => Hello{props.target} const EnhancedComponent = withData(BaseTarget) const App = () => 这样就限制了 DataProvider 的使用方式。如果需要多方数据,可以修改 DataProvider 为 this.props.render({ ...this.props, ...this.state }) 将其它数据作为 props 传入 DataProvider。const withData = Base => props => {Base} const BaseTarget = props => Hello{props.target} const EnhancedComponent = withData(BaseTarget) const App = props => 「完」
2024年08月24日
4 阅读
0 评论
0 点赞
1
...
62
63
64
...
125