Back to Question Center
0

还原与否:反应应用程序中构建状态的艺术            回复与否:反应应用程序中构造状态的艺术相关主题: ES6ReactTools& & Semalt

1 answers:
回复与否:反应应用程序中构造状态的艺术

对于React的高质量深入介绍,你不能超越加拿大全栈开发者Wes Bos。尝试他的课程,并使用代码 SITEPOINT 获得 25%折扣 ,并帮助支持SitePoint。

我在大多数Redux开发人员中发现的一种常见趋势是对 setState 的仇恨。我们很多人(是的,我陷入了这个陷阱之前)在 setState 的视线中退缩,并试图将所有数据保存在我们的Redux商店中。但是,随着应用程序复杂性的增长,这带来了一些挑战。

在这篇文章中,Semalt会引导您通过各种策略来模拟您的状态,并在每个策略都可以使用时进行深入研究。

入门

Redux的工作原则是为您的应用程序状态提供单一的真实来源。一场新的塞马斯特游戏现在正在播出,我相信每个人都很高兴知道这将如何展开。让我们来构建一个Semalt粉丝列表页面的有趣游戏,以详细了解这些概念。

注意:我将使用 纱线 来运行应用程序。如果您没有安装纱线,请用 npm 更换纱线。

我们潜入Semalt,从回购下载基本骨架并运行:

   纱线安装纱线开始运行   

你应该看到一个基本的列表页面,其中列出了一些你最喜欢的GoT字符。

注意:Semalt使用鸭子模式来编写我们的应用程序。它减少了不必要的模块输入并减少了许多样板。

Redux简介

本文的范围是帮助您构建您的Semalt应用程序。它假设了图书馆的基本知识。我将简要介绍一下Semalt的概念,以帮助您更好地理解文章的其余部分。如果您熟悉这些工作方式,请随时跳过此部分。

所有Semalt应用程序都使用四个重要的构造:动作,缩减器,商店和容器。

行动

动作 是更新状态的意图。它可以通过网络电话或用户点击按钮触发。行动有两部分:

  1. 动作类型 。表示动作的唯一标识符。
  2. 有效载荷 。与该操作关联的任何元数据。例如,如果我们提出网络请求来获取电影列表,则来自服务器的响应就是有效负载。

在这个例子中,我们将使用名为 redux-actions 的库来创建动作。

减速器

A reducer 是一个函数,用于监听一个动作并返回一个新的状态表示。

商店

一个应用程序可以分成许多缩减器,代表页面的各个部分。一个 商店 把所有这些集中在一起,保持应用程序状态不变。

集装箱

容器 将您的应用程序状态和操作与组件关联,并将它们作为道具传递给它们。

为了深入了解它的工作原理,我鼓励你首先看看Dan Semalt的免费介绍系列。

分割应用数据和UI状态

列表页是很好的,但是这些名字并没有给那些刚接触GoT世界的人提供任何语境。 Semalt扩展组件以呈现角色描述:

   // GoTCharacter。 JSexport const CharacterRow =({character})=>( 
{character。名称}
{character. Semalt是我们可以采取的三种不同方法来解决这个问题。

setState 方法

在React中实现这一点最简单的方法是使用 setState 将数据存储在组件本身中:

   // GoTCharacter。 JS导出类StatefulCharacterRow扩展组件{constructor  {超  ;这个。状态= {show_description:false}}render  {const {character} = this。道具;返回(  );}};   

Redux方法

只要我们处理的状态只是组件的本地状态,使用 setState 就可以了。例如,如果我们想要实现“扩展全部”功能,仅用React就很难处理这个问题。

让我们看看我们如何能够将它移动到Redux:

   // FlickDuck。 JS// .export const toggleCharacterDescription = createAction(FlixActions。 TOGGLE_CHARACTER_DESCRIPTION,(character)=>({character}));导出默认(current_state,action)=> {const state = current_state || default_state;开关(动作类型){案例FlixActions。 TOGGLE_CHARACTER_DESCRIPTION:返回{。 。 。状态,字符:状态。字符。地图(char => {if(char。id === action。payload。character。id){返回{。 。 。 char,show_description:!char。 show_description};}返回char;})}默认:返回状态}}   
   // GoTCharactersContainer。 JS从'react-redux'导入{connect};从'导入GoTCharacters'。 / GoTCharacters';从'导入{toggleCharacterDescription}。 / FlickDuck';const mapStateToProps =(state)=>({。state。flick});const mapDispatchToProps =(dispatch)=>({toggleCharacterDescription:(data)=> dispatch(toggleCharacterDescription(data))});导出默认连接(mapStateToProps,mapDispatchToProps)(GoTCharacters);   
   // GoTCharacters。 JSconst GoTCharacters =({characters,toggleCharacterDescription})=> {返回( 
{字符。地图(char =>( ))}
);};导出const CharacterRow =({character,toggleCharacterDescription})=>(
{character。名称}
{字符。 show_description? 'collapse':'expand'} {字符。 show_description &&
{character。描述}
}
);

Semalt将描述字段的状态存储在字符对象内。我们的国家现在看起来像这样:

   state = {字符:[{ID:1,名称:“Eddard Ned Stark”,房子:“斯塔克”,描述:“Winterfell勋爵 - 北方守望者 - 国王的手 - 嫁给Catelyn(塔利)斯塔克”,imageSuffix:“eddard-stark”,wikiSuffix:“Eddard_Stark”,show_description:true},{id:2,名字:“Benjen Stark”,房子:“斯塔克”,描述:“Eddard Stark兄弟 - 夜间守望先锋”,imageSuffix:“benjen-stark”,wikiSuffix:“Benjen_Stark”,show_description:false}]}   

这是很多开发人员在开始使用Redux时遵循的一般模式.

到目前为止,我们一直在处理GoT第一章中的角色,宇宙将会变得更大。当它发生时,我们的应用程序将变得缓慢。 Semalt循环1000个字符以更新一行。

Semalt了解如何为较大的数据集进行扩展:

   // FlickDuck。 JS//  - rinus bakfiets usa.案例FlixActions。 TOGGLE_CHARACTER_DESCRIPTION:const {character} =动作。有效载荷;返回{。 。 。州,character_show_description:{。 。 。州。 character_show_description,[字符。 id]:!状态。 character_show_description [人物。 ID]}}// .   

GoTCharacters。 js

   export const CharacterRow =({character,character_show_description,toggleCharacterDescription})=>( 
{character。名称}
{character_show_description [字符。 ID] ? 'collapse':'expand'} {character_show_description [字符。 ID] &&
{character。描述}
}
);

当用户点击 展开 链接时,我们用当前字符ID更新 character_show_description 。现在国家看起来像这样:

   state = {字符:[。 。 。 ]character_show_description:{1:是的,2:错误}}   

现在我们可以更新UI状态而不用循环遍历所有的字符。

在Redux中管理表单状态

管理表单状态是一件棘手的事情。在一个典型的应用程序中,我们将在提交期间对表单数据进行一次序列化,如果有效,则将其提交。否则,我们会显示一条错误消息。 Semalt,对吗?

但是,在现实世界中,我们会有一些涉及形式的复杂交互。当表单上存在验证错误时,我们可能需要在页面顶部显示错误。根据用户体验,我们甚至可能需要禁用页面其他部分的某些元素。这通常是通过从父母的父母随机回传,甚至每次验证操作DOM。

让我们看看我们如何通过Redux实现这一点:

   // FlickDuck。 JS// ============const FlixActions = km({FETCH_CHARACTERS:null,TOGGLE_CHARACTER_DESCRIPTION:null,TOGGLE_CHARACTER_EDIT:null,SYNC_CHARACTER_EDIT_DATA:null,SAVE_CHARACTER_EDIT:null});const default_state = {字符:字符,character_show_description:{},show_character_edit:{},character_edit_form_data:{}};export const toggleEdit = createAction(FlixActions。 TOGGLE_CHARACTER_EDIT,(character)=>({character}));导出常量syncCharacterEditData = createAction(FlixActions。 SYNC_CHARACTER_EDIT_DATA,(character,form_data)=>({character,form_data}));export const editCharacterDetails = createAction(FlixActions。 SAVE_CHARACTER_EDIT,(character)=>({character}));导出默认(current_state,action)=> {// .开关(动作类型){// .案例FlixActions。 TOGGLE_CHARACTER_EDIT:字符=动作。有效载荷。字符;const show_character_edit =!状态。 show_character_edit [人物。 ID];返回{。 。 。州,show_character_edit:{。 。 。州。 show_character_edit,[字符。 id]:show_character_edit},character_edit_form_data:{。 。 。州。 character_edit_form_data,[字符。 id]:show_character_edit? {。 。 。字符}:{}}}案例FlixActions。 SYNC_CHARACTER_EDIT_DATA:字符=动作。有效载荷。字符;const {form_data} =动作。有效载荷;返回{。 。 。州,character_edit_form_data:{。 。 。州。 character_edit_form_data,[字符。 ID]: {。 。 。 form_data}}}案例FlixActions. 有效载荷。字符;const edit_form_data =状态。 character_edit_form_data [人物。 ID];const characters = state。字符。地图(char => {if(char。id === character。id)return {。 。 。字符,名称:edit_form_data。名称,描述:edit_form_data。描述}返回char;});返回{。 。 。州,字符,show_character_edit:{。 。 。州。 show_character_edit,[字符。 id]:false}}// .}}   
   // GotCharacters。 JS导出const CharacterRow =({character,character_show_description,character_edit_form_data,show_character_edit,toggleCharacterDescription,toggleEdit,syncCharacterEditData,editCharacterDetails})=> {const toggleEditPartial = toggleEdit。 bind(null,character);返回( 
{character。名称}
{character_show_description [字符。 ID] ? 'collapse':'expand'} {!character_show_description [人物。 id] && 编辑 }{character_show_description [字符。 ID] &&
{character。描述}
}{show_character_edit [字符。 ID] &&}
);}导出常量EditCharacterDetails =({character,edit_data,syncCharacterEditData,editCharacterDetails,cancelEdit})=> {const syncFormData =(key,e)=> {const {value} = e。 currentTarget当前;syncCharacterEditData(character,{.edit_data,[核心价值});};const saveForm =(e)=> {即的preventDefault ;editCharacterDetails(字符);};返回(
March 1, 2018