笔记本键盘 发疯_如何使用ImmutableJS而不会发疯

2024-01-12 08:20

本文主要是介绍笔记本键盘 发疯_如何使用ImmutableJS而不会发疯,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

笔记本键盘 发疯

如果您在Javascript生态系统中,则可能会知道有很多新库,并且仍在开发良好实践,尤其是在ReactJS生态系统中。

如果您正在使用ReactJS开发单页应用程序,并且正在使用Redux进行状态管理 ,那么您可能听说过ImmutableJS。

它是一个库,可帮助开发人员保持其状态不变,从而避免难以发现的错误。

不仅如此,它还有助于React在适当的时间重新渲染组件。 您可能知道React使用浅层比较来了解某些道具是否已更改。

当您将结构化数据传递到组件(数组,对象)时,这可能会带来问题。 React不会执行深度比较(因为它很昂贵),因此您可能会遇到意想不到的行为。

// In reducer.js
const state = {
usersPage: {
loading: false,
isFetched: false,
list: [],
},
companiesPage: {
loading: false,
isFetched: false,
list: [],
},
};
// In UsersPage.js
class UsersPage extends React.Component {
render() {
const { loading, list } = this.props.usersPage;
    return (
<div>
{ loading && <LoadingIndicator /> }
{ !loading && <UsersTable list={list} /> }
</div>
);
}
}
function mapStateToProps(state) {
return {
usersPage: selectors.selectUsersPage(state) ,
};
}
// In selectors.js
const selectUsersPage = (state) => state.usersPage;

考虑上面的代码,一切似乎都很好。 但是,如果您以错误的方式实施状态更新,例如 您不会创建新对象,React不会更新您的组件。 例如:

// Incorrect implementation
function reducer(state, action) {
switch(action.type) {
case 'USERS_LOADED':
state.usersPage.list = action.payload;
state.usersPage.loading = false;
state.usersPage.isFetched = true;
return state;
default:
return state;
}
}
// Correct implementation
function reducer(state, action) {
switch(action.type) {
case 'USERS_LOADED':
return {
...state,
usersPage: Object.assign({}, state.usersPage, {
list: Object.payload,
loading: false,
isFetched: true,
}),
};
default:
return state;
}
}

正如您在上面的代码中看到的那样,事情很容易变得棘手。 您必须确保在保留状态的其他分支并正确更新当前分支中的变量的同时返回新对象。

现在,让我们看一下ImmutableJS的实现:

import { fromJS } from 'immutable';
const state = fromJS({
usersPage: {
loading: false,
isFetched: false,
list: [],
},
companiesPage: {
loading: false,
isFetched: false,
list: [],
},
});
function reducer(state, action) {
switch(action.type) {
case 'USERS_LOADED':
return state
.setIn(['usersPage', 'list'], fromJS(action.payload))
.setIn(['usersPage', 'isFetched'], true)
.setIn(['usersPage', 'loading'], false)
;
default:
return state;
}
}

这种语法使事情变得更易于阅读和维护。 每当更改状态时,ImmutableJS都会返回一个新对象。

但是,您将必须使用ImmutableJS getter来获取值:

// In UsersPage.js
class UsersPage extends React.Component {
render() {
const { usersPage } = this.props;
const loading = usersPage.get('loading');
const list = usersPage.get('list').toJS();
    return (
<div>
{ loading && <LoadingIndicator /> }
{ !loading && <UsersTable list={list} /> }
</div>
);
}
}
function mapStateToProps(state) {
return {
usersPage: selectors.selectUsersPage(state),
};
}
// In selectors.js
const selectUsersPage = (state) => state.get('usersPage');

更糟糕的是,有时ImmutableJS对象会更深地泄漏到您的组件中,甚至泄漏到您的呈现组件中(请toJS() )。 这通常是人们反对使用ImmutableJS的原因之一。

当您计划发布软件包时,情况甚至更糟。 您不想让开发人员使用某些库来束缚使用它的开发人员的双手。

那么如何结合两全其美呢?

重新选择救援!

Reselect是一个很棒的库,可以帮助您解决此问题。

让我们首先了解Reselect的用途:

用于Redux的简单“选择器”库。

  • 选择器可以计算派生数据,从而允许Redux存储最小可能状态。
  • 选择器是有效的。 除非更改了其中一个参数,否则不会重新计算选择器。
  • 选择器是可组合的。 它们可以用作其他选择器的输入。

和我裸一下。 考虑以下代码:

import { createSelector } from 'reselect';
const selectUsersPageDomain = (state) => state.get('usersPage');
const makeSelectUsersPage = createSelector(
selectUsersPageDomain,
(substate) => substate.toJS(),
);

然后,您可以再次使用纯JS语法:

import { createStructuredSelector } from 'reselect';
class UsersPage extends React.Component {
render() {
const { loading, list } = this.props.usersPage;
return (
<div>
{ loading && <LoadingIndicator /> }
{ !loading && <UsersTable list={list} /> }
</div>
);
}
}
const mapStateToProps = createStructuredSelector ({
usersPage: selectors.makeSelectUsersPage(),
});

如果userPage分支中没有任何变化,则选择器不会重新计算其值,React 也不会触发组件渲染。

如您所见,使用此策略,您可以将两个方面的优点结合起来。

但是有一件重要的事情,我没有谈论过,并没有明显的好处:

使用ImmutableJS更新某些分支时,所有未触及的分支均保持不变:

const { fromJS } = require('immutable');
const state = fromJS({
usersPage: {
loading: false,
isFetched: false,
list: [],
},
companiesPage: {
loading: false,
isFetched: false,
list: [],
},
});
console.log('Updating usersPage branch');
const state1 = state.setIn(['usersPage', 'loading'], true);
state.get('usersPage') === state1.get('usersPage'); // false
state.get('companiesPage') === state1.get('companiesPage'); // true
state === state1; // false
console.log('Updating companiesPage branch');
const state2 = state1.setIn(['companiesPage', 'loading'], true);
state1.get('usersPage') === state2.get('usersPage'); // true
state1.get('companiesPage') === state2.get('companiesPage'); // false
state1 === state2; // false

注意:我删除了 console.log 语句以缩短行数。

如果您查看代码,将会看到未更新的分支保持不变->因此, reselect选择选择器将不会触发更新。 仅更新分支的选择器将被更新

但是状态的根也被更新了! 因此,在编写选择器时必须小心一点:

// In reducer.js
const { fromJS } = require('immutable');
const state = fromJS({
pages: { // We put our pages 1 more level deeper
usersPage: {
loading: false,
isFetched: false,
list: [],
},
companiesPage: {
loading: false,
isFetched: false,
list: [],
},
}
});
// In selectors.js
// Incorrect implementation
import { createSelector } from 'reselect';
const selectPagesDomain = (state) => state.get('pages');
const selectUsersPageDomain = (state) => state.get('usersPage');
const selectCompaniesPageDomain = (state) => state.get('companiesPage');
const makeSelectUsersPage = createSelector(
selectPagesDomain , // source of problem
selectUsersPageDomain,
(substate) => substate.toJS(),
);
const makeSelectCompaniesPage = createSelector(
selectPagesDomain , // source of problem
selectCompaniesPageDomain,
(substate) => substate.toJS(),
);

如果您以这种方式实现选择器,则仅在其中之一中更改值时,都会同时触发makeSelectCompaniesPagemakeSelectUsersPage 。 这可能是您不想要的东西。

他们为什么被触发? 回顾以下规则:

  • 选择器是有效的。 除非更改了其中一个参数,否则不会重新计算选择器。

由于selectPagesDomain如果分支的任何一个已更改,将返回不同的值,因此reselect每次都会重新计算两个选择器。

这是正确的实现:

// Correct implementation
import { createSelector } from 'reselect';
const selectUsersPageDomain = (state) => state.getIn(['pages', 'usersPage']) ;
const selectCompaniesPageDomain = (state) => state.getIn(['pages', 'companiesPage']) ;
const makeSelectUsersPage = createSelector(
selectUsersPageDomain ,
(substate) => substate.toJS(),
);
const makeSelectCompaniesPage = createSelector(
selectCompaniesPageDomain ,
(substate) => substate.toJS(),
);

您希望选择最接近要在选择器中使用的数据的路径,以防止在更改其他分支时重新计算。

如果您成功到这里,恭喜!

让我们放在一起:

 // In reducer.js
const { fromJS } = require('immutable');
const state = fromJS({
pages: {
usersPage: {
loading: false,
isFetched: false,
list: [],
},
companiesPage: {
loading: false,
isFetched: false,
list: [],
},
}
});
function reducer(state, action) {
switch(action.type) {
case 'USERS_LOADED':
return state
.setIn(['usersPage', 'list'], fromJS(action.payload))
.setIn(['usersPage', 'isFetched'], true)
.setIn(['usersPage', 'loading'], false)
;
case 'COMPANIES_LOADED':
return state
.setIn(['companiesPage', 'list'], fromJS(action.payload))
.setIn(['companiesPage', 'isFetched'], true)
.setIn(['companiesPage', 'loading'], false)
;
default:
return state;
}
}
export default reducer;
 // In selectors.js
import { createSelector } from 'reselect';
const selectUsersPageDomain = (state) => state.getIn(['pages', 'usersPage']);
const selectCompaniesPageDomain = (state) => state.getIn(['pages', 'companiesPage']);
export const makeSelectUsersPage = createSelector(
selectUsersPageDomain,
(substate) => substate.toJS(),
);
export const makeSelectCompaniesPage = createSelector(
selectCompaniesPageDomain,
(substate) => substate.toJS(),
);
 // In UsersPage.js
import { createStructuredSelector } from 'reselect';
import * as selectors from './selectors';
class UsersPage extends React.Component {
render() {
const { loading, list } = this.props.usersPage;
    return (
<div>
{ loading && <LoadingIndicator /> }
{ !loading && <UsersTable list={list} /> }
</div>
);
}
}
const mapStateToProps = createStructuredSelector({
usersPage: selectors.makeSelectUsersPage(),
});
export default connect(mapStateToProps)(UsersPage);
 // In CompaniesPage.js
import { createStructuredSelector } from 'reselect';
import * as selectors from './selectors';
class CompaniesPage extends React.Component {
render() {
const { loading, list } = this.props.companiesPage;
    return (
<div>
{ loading && <LoadingIndicator /> }
{ !loading && <CompaniesTable list={list} /> }
</div>
);
}
}
const mapStateToProps = createStructuredSelector({
companiesPage: selectors.makeSelectCompaniesPage(),
});
export default connect(mapStateToProps)(CompaniesPage);

而已!

现在,您可以使用ImmutableJS的所有优点,而无需在容器或呈现组件中使用其getter。

最重要的是,您获得了重新选择库的优势,这可以帮助您提高选择器的效率。

让我知道你的想法!

参考文献:

Redux
如果您不使用模块捆绑器,也可以。 npm软件包包括预编译的生产和开发… redux.js.org
reactjs /重新选择
重新选择 -Redux github.com的选择器库

翻译自: https://hackernoon.com/how-to-use-immutablejs-without-going-crazy-bfcb805a0043

笔记本键盘 发疯

这篇关于笔记本键盘 发疯_如何使用ImmutableJS而不会发疯的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/597289

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

【北交大信息所AI-Max2】使用方法

BJTU信息所集群AI_MAX2使用方法 使用的前提是预约到相应的算力卡,拥有登录权限的账号密码,一般为导师组共用一个。 有浏览器、ssh工具就可以。 1.新建集群Terminal 浏览器登陆10.126.62.75 (如果是1集群把75改成66) 交互式开发 执行器选Terminal 密码随便设一个(需记住) 工作空间:私有数据、全部文件 加速器选GeForce_RTX_2080_Ti

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念