笔记本键盘 发疯_如何使用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

相关文章

使用Docker构建Python Flask程序的详细教程

《使用Docker构建PythonFlask程序的详细教程》在当今的软件开发领域,容器化技术正变得越来越流行,而Docker无疑是其中的佼佼者,本文我们就来聊聊如何使用Docker构建一个简单的Py... 目录引言一、准备工作二、创建 Flask 应用程序三、创建 dockerfile四、构建 Docker

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

Python使用pip工具实现包自动更新的多种方法

《Python使用pip工具实现包自动更新的多种方法》本文深入探讨了使用Python的pip工具实现包自动更新的各种方法和技术,我们将从基础概念开始,逐步介绍手动更新方法、自动化脚本编写、结合CI/C... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

C#中Guid类使用小结

《C#中Guid类使用小结》本文主要介绍了C#中Guid类用于生成和操作128位的唯一标识符,用于数据库主键及分布式系统,支持通过NewGuid、Parse等方法生成,感兴趣的可以了解一下... 目录前言一、什么是 Guid二、生成 Guid1. 使用 Guid.NewGuid() 方法2. 从字符串创建

Python使用python-can实现合并BLF文件

《Python使用python-can实现合并BLF文件》python-can库是Python生态中专注于CAN总线通信与数据处理的强大工具,本文将使用python-can为BLF文件合并提供高效灵活... 目录一、python-can 库:CAN 数据处理的利器二、BLF 文件合并核心代码解析1. 基础合

Python使用OpenCV实现获取视频时长的小工具

《Python使用OpenCV实现获取视频时长的小工具》在处理视频数据时,获取视频的时长是一项常见且基础的需求,本文将详细介绍如何使用Python和OpenCV获取视频时长,并对每一行代码进行深入解析... 目录一、代码实现二、代码解析1. 导入 OpenCV 库2. 定义获取视频时长的函数3. 打开视频文

Spring IoC 容器的使用详解(最新整理)

《SpringIoC容器的使用详解(最新整理)》文章介绍了Spring框架中的应用分层思想与IoC容器原理,通过分层解耦业务逻辑、数据访问等模块,IoC容器利用@Component注解管理Bean... 目录1. 应用分层2. IoC 的介绍3. IoC 容器的使用3.1. bean 的存储3.2. 方法注

Python内置函数之classmethod函数使用详解

《Python内置函数之classmethod函数使用详解》:本文主要介绍Python内置函数之classmethod函数使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 类方法定义与基本语法2. 类方法 vs 实例方法 vs 静态方法3. 核心特性与用法(1编程客