将 Redux 与模型一起使用
Using Redux with models
我已经开始将 Redux 与 React 结合使用,我非常喜欢它。但是,我目前遇到的问题是,除了状态之外,我还需要 store/use 整个应用程序中的更多信息。
在这种特定情况下,我有一个模型,其状态是从 API 中获取的。这个模型也有一些关于它自己的信息,例如如何在屏幕上显示 属性 "name" => "Name of the blabla"。我了解如何使用 Redux 来处理状态,但是我很难理解如何处理我仍然需要在整个应用程序中传播但实际上不是状态的其他信息。
根据 Redux,State 是唯一的 "source of truth"。而且它不应该有重复(这会导致不一致)。
所以你的状态应该存储 name
,而不是 computed 标签 属性.
的确,"Name of the blabla" 是您的 Name 值的一个函数(在数学意义上),如果它们不同(例如,如果在某些时候 name === 'foo' 但标签是 'Name of the bar' 而不是 'Name of the foo'),那么你有问题...
所以我会做的,只是将最小值存储在您的状态(在这种情况下为名称),然后直接在您需要的组件中计算标签。
如果您需要重新使用它,则创建一个只将您的名字作为道具的组件,并使用 "Name of the blablaba" 渲染一个字符串(如果 name = blabla 我想)。
如果您需要更复杂的计算(比如您有多个标签、日期计算等),您始终可以创建一个函数,将您的状态作为输入,并在输出中吐出您的 "Model" 以及所有内容计算。
Redux 本质上非常实用,所以你不妨拥抱它:)
我知道我有点迟到了,但我认为有人可能会使用答案。在使用 React 多年后,到目前为止对我有用的是拥有一个类似于这样的结构:
- 状态:设置我的数据的结构(或 'schemas')。
- 操作:更改此状态。这些操作可以处理同步或异步操作。
- Sagas:它们处理异步操作。
- 选择器:它们处理 view/for API.
所需的数据结构
- 常量:不会随时间变化且添加到我的状态中没有意义的其他数据。
所以说我的应用程序流程是这样的:
调度 ACTION
=> 如果该操作是异步的,则 SAGA
正在侦听并执行获取操作 => 此传奇将更新保存到 STATE
=> [React 组件层从现在开始on] => 如果我的视图出于某种原因需要来自我的状态的不同格式的数据,我将通过 SELECTOR
发送它,这将改变该格式 => 然后我将这个新的解析数据附加到我的容器组件。
另一种流程可能是您需要 state
中没有的静态数据。因此,我会将其保存在一个单独文件中的对象中,并将其直接导入到我的容器组件中(我从不直接在我的 children/presentational 组件中导入任何内容。只有其他组件。数据在单独的层中处理比组件)。
我现在能想到的第三种流程是当你需要对你的 API 进行 POST 并且无论出于何种原因你的状态中的数据在这样做之前需要一些解析.在那种情况下,我会做与第一个示例中相同的事情,但相反:调度一个 ACTION
=> 由 SAGA
=> 处理,然后再进行获取我会带上我的数据为我的 POST 构建(sagas 有一个名为 select
的方法来帮助您在这里使用选择器)=> 然后我将执行异步操作 => 相应地更新状态。
以防万一你不知道我所说的选择器或传奇故事的意思,这里有一些链接:
我认为模型对于基于 Redux 的应用程序和任何其他系统都是必要的。
模型是系统的词汇。模型为代码库带来理智。没有它们,代码库看起来就像是一系列疯狂扭曲的想法。
您可以使用状态函数来填充 ReactJS+Redux 应用程序中模型的需要。
就像模型保存数据和方法一样,这些对象只保存可应用于状态的函数。
阅读此处:https://medium.com/@nshnt/state-functions-for-modeling-with-redux-a9b9d452a631。
这是带有状态函数的著名 Redux TODO 应用示例:
todo_reducer.js :
import TODO from './todo_state';
const todoListReducer = (state=TODO.initialState(), action)=>{
switch(action.type){
case 'ADD_TODO' :
return TODO.addTask(state, action.taskName);
case 'FINISHED_TODO':
return TODO.setFinished(state, action.taskID );
case 'PENDING_TODO':
return TODO.setPending(state, action.taskID );
default :
return state;
}
};
export default todoListReducer;
todo-state.js :
export default {
initialState: () => [],
addTask: (todoList, name)=> todoList.concat({id: todoList.length, name: name}),
setFinished: (todoList, taskId) => (
todoList.map(task=> task.id === taskId ? {...task, complete: true} : task)
),
setPending: (todoList, taskId) => (
todoList.map(task=> task.id === taskId ? {...task, complete: false} : task)
),
pending: todoList=> todoList.filter(task=> !task.complete)
};
如果组件需要一些状态操作,我也在组件中使用这些状态函数。
todo_list.js :
import React from 'react';
import {connect} from 'react-redux';
import TODO from './todo_state';
const TodoList = ({tasks, showCompletedTasks, toggleTodo})=> {
const toListElement = (task) => (
<li key={task.id}>
<input type="checkbox" checked={task.complete} onChange={(e)=> toggleTodo(task)}/>
<label>{task.name} {task.complete ? "Complete" : "Pending"}</label>
</li>
);
const visibleTaskList =
(showCompletedTasks ? tasks
: TODO.pending(tasks)).map(toListElement);
return (
<ul className="todo-list">
{visibleTaskList}
</ul>
);
}
.....
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
使用重新选择
Reselect 是一个简单的库,位于您的应用程序中。它的主要功能是聚合来自 redux 存储的数据。
创建重选函数
取自https://medium.com/@parkerdan/react-reselect-and-redux-b34017f8194c
import { createSelector } from 'reselect'
// selector
const getBar = (state) => state.foo.bar
// reselect function
export const getBarState = createSelector(
[ getBar ],
(bar) => bar
)
想法是将组件与 redux-connect
或 map state to props
连接,但不是直接使用商店,而是将商店传递给选择器。此选择器将具有一个功能,可让您聚合数据或以任何您喜欢的方式转换数据。
import React from 'react'
import { connect } from 'react-redux'
import { getBarState } from '../selectors'
const mapStateToProps = (state) => {
return {
bar: getBarState(state)
}
}
这种方法的优点是您可以很容易地在任何组件上重用选择器。您在数据到达组件 (Separation of concerns principal) 之前对其进行操作。这为您提供了 2 大优势。
- 首先,您的 redux 存储可以保持不受重复或计算数据的污染。
- 其次,您的组件可以构建为期望对它们立即有意义的数据结构。
结论
Reselect 帮助您的 React 应用变得更加结构化。
我已经开始将 Redux 与 React 结合使用,我非常喜欢它。但是,我目前遇到的问题是,除了状态之外,我还需要 store/use 整个应用程序中的更多信息。
在这种特定情况下,我有一个模型,其状态是从 API 中获取的。这个模型也有一些关于它自己的信息,例如如何在屏幕上显示 属性 "name" => "Name of the blabla"。我了解如何使用 Redux 来处理状态,但是我很难理解如何处理我仍然需要在整个应用程序中传播但实际上不是状态的其他信息。
根据 Redux,State 是唯一的 "source of truth"。而且它不应该有重复(这会导致不一致)。
所以你的状态应该存储 name
,而不是 computed 标签 属性.
的确,"Name of the blabla" 是您的 Name 值的一个函数(在数学意义上),如果它们不同(例如,如果在某些时候 name === 'foo' 但标签是 'Name of the bar' 而不是 'Name of the foo'),那么你有问题...
所以我会做的,只是将最小值存储在您的状态(在这种情况下为名称),然后直接在您需要的组件中计算标签。
如果您需要重新使用它,则创建一个只将您的名字作为道具的组件,并使用 "Name of the blablaba" 渲染一个字符串(如果 name = blabla 我想)。
如果您需要更复杂的计算(比如您有多个标签、日期计算等),您始终可以创建一个函数,将您的状态作为输入,并在输出中吐出您的 "Model" 以及所有内容计算。
Redux 本质上非常实用,所以你不妨拥抱它:)
我知道我有点迟到了,但我认为有人可能会使用答案。在使用 React 多年后,到目前为止对我有用的是拥有一个类似于这样的结构:
- 状态:设置我的数据的结构(或 'schemas')。
- 操作:更改此状态。这些操作可以处理同步或异步操作。
- Sagas:它们处理异步操作。
- 选择器:它们处理 view/for API. 所需的数据结构
- 常量:不会随时间变化且添加到我的状态中没有意义的其他数据。
所以说我的应用程序流程是这样的:
调度 ACTION
=> 如果该操作是异步的,则 SAGA
正在侦听并执行获取操作 => 此传奇将更新保存到 STATE
=> [React 组件层从现在开始on] => 如果我的视图出于某种原因需要来自我的状态的不同格式的数据,我将通过 SELECTOR
发送它,这将改变该格式 => 然后我将这个新的解析数据附加到我的容器组件。
另一种流程可能是您需要 state
中没有的静态数据。因此,我会将其保存在一个单独文件中的对象中,并将其直接导入到我的容器组件中(我从不直接在我的 children/presentational 组件中导入任何内容。只有其他组件。数据在单独的层中处理比组件)。
我现在能想到的第三种流程是当你需要对你的 API 进行 POST 并且无论出于何种原因你的状态中的数据在这样做之前需要一些解析.在那种情况下,我会做与第一个示例中相同的事情,但相反:调度一个 ACTION
=> 由 SAGA
=> 处理,然后再进行获取我会带上我的数据为我的 POST 构建(sagas 有一个名为 select
的方法来帮助您在这里使用选择器)=> 然后我将执行异步操作 => 相应地更新状态。
以防万一你不知道我所说的选择器或传奇故事的意思,这里有一些链接:
我认为模型对于基于 Redux 的应用程序和任何其他系统都是必要的。
模型是系统的词汇。模型为代码库带来理智。没有它们,代码库看起来就像是一系列疯狂扭曲的想法。
您可以使用状态函数来填充 ReactJS+Redux 应用程序中模型的需要。 就像模型保存数据和方法一样,这些对象只保存可应用于状态的函数。
阅读此处:https://medium.com/@nshnt/state-functions-for-modeling-with-redux-a9b9d452a631。
这是带有状态函数的著名 Redux TODO 应用示例:
todo_reducer.js :
import TODO from './todo_state';
const todoListReducer = (state=TODO.initialState(), action)=>{
switch(action.type){
case 'ADD_TODO' :
return TODO.addTask(state, action.taskName);
case 'FINISHED_TODO':
return TODO.setFinished(state, action.taskID );
case 'PENDING_TODO':
return TODO.setPending(state, action.taskID );
default :
return state;
}
};
export default todoListReducer;
todo-state.js :
export default {
initialState: () => [],
addTask: (todoList, name)=> todoList.concat({id: todoList.length, name: name}),
setFinished: (todoList, taskId) => (
todoList.map(task=> task.id === taskId ? {...task, complete: true} : task)
),
setPending: (todoList, taskId) => (
todoList.map(task=> task.id === taskId ? {...task, complete: false} : task)
),
pending: todoList=> todoList.filter(task=> !task.complete)
};
如果组件需要一些状态操作,我也在组件中使用这些状态函数。
todo_list.js :
import React from 'react';
import {connect} from 'react-redux';
import TODO from './todo_state';
const TodoList = ({tasks, showCompletedTasks, toggleTodo})=> {
const toListElement = (task) => (
<li key={task.id}>
<input type="checkbox" checked={task.complete} onChange={(e)=> toggleTodo(task)}/>
<label>{task.name} {task.complete ? "Complete" : "Pending"}</label>
</li>
);
const visibleTaskList =
(showCompletedTasks ? tasks
: TODO.pending(tasks)).map(toListElement);
return (
<ul className="todo-list">
{visibleTaskList}
</ul>
);
}
.....
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
使用重新选择
Reselect 是一个简单的库,位于您的应用程序中。它的主要功能是聚合来自 redux 存储的数据。
创建重选函数
取自https://medium.com/@parkerdan/react-reselect-and-redux-b34017f8194c
import { createSelector } from 'reselect'
// selector
const getBar = (state) => state.foo.bar
// reselect function
export const getBarState = createSelector(
[ getBar ],
(bar) => bar
)
想法是将组件与 redux-connect
或 map state to props
连接,但不是直接使用商店,而是将商店传递给选择器。此选择器将具有一个功能,可让您聚合数据或以任何您喜欢的方式转换数据。
import React from 'react'
import { connect } from 'react-redux'
import { getBarState } from '../selectors'
const mapStateToProps = (state) => {
return {
bar: getBarState(state)
}
}
这种方法的优点是您可以很容易地在任何组件上重用选择器。您在数据到达组件 (Separation of concerns principal) 之前对其进行操作。这为您提供了 2 大优势。
- 首先,您的 redux 存储可以保持不受重复或计算数据的污染。
- 其次,您的组件可以构建为期望对它们立即有意义的数据结构。
结论
Reselect 帮助您的 React 应用变得更加结构化。