我在多个页面的表格中显示服务器驱动的数据。
我目前有下表操作
pageChange
pageSizeChange
sort
load
loaded
我在一些需要触发加载的页面上有过滤器。
我有多个使用此功能的实体,它们将共享上述大部分逻辑,但需要单独的加载功能定义。
我的想法是采取将表 ID 作为参数的操作,然后具有一个 createTableReducer 函数,该函数也将采用此 ID 并将表节点挂载到实体中,类似于 react-redux-form 中的 createModelReducer|
如果不使用像 redux saga 这样的东西,我怎么能从我的通用操作中触发实体特定的加载操作?
我想知道如何创建一个高阶组件并将其传递给加载函数,但我认为这不会解决我的问题。我也可以从表组件本身调用更改操作和加载操作,但这似乎不是一个好的解决方案。
最佳答案
所以,这是一个非常开放的问题,实现它的可能性几乎是无限的……但是,无论如何我都会尝试一下。这个答案不是教条,它只是一种可能的实现方式。
让我们首先希望我们可以随心所欲地放置我们的 table 。要将一个表与另一个表区分开来,我们所要做的就是传递一个 tableId 属性,该属性将 Table 链接到存储中的相应数据。
<Table tableId='customers' />
<Table tableId='products' />
<Table tableId='orders' />
<Table tableId='transactions' />
接下来,让我们定义一个要使用的状态形状。每个顶级键都与我们希望为其存储数据的 tableId 相匹配。你可以把这个形状做成任何你喜欢的形状,但我提供这个是为了让你不必做太多的心理想象,因为我在后面的代码中引用了一些东西。您还可以根据需要命名顶级 tableId 键,只要您一致地引用它们即可。
{
customers: {
page: 0,
sortBy: 'id',
cols: [
{id: 'id', name: 'name'},
{id: 'username', name: 'Username'},
{id: 'first_name', name: 'First Name'},
{id: 'last_name', name: 'Last Name'},
...
],
rows: [
{id: 1, username: 'bob', first_name: 'Bob', last_name: 'Smith', ...},
...
]
},
products: {
...
},
orders: {
...
}
...
}
现在,让我们解决最困难的部分:Table 容器。一次要消化的东西很多,但别担心,我会逐一分解重要的部分。
容器/Table.js
import React from 'react';
import {connect} from 'react-redux';
import actions as * from './actions/';
const _Table = ({cols, rows, onClickSort, onClickNextPage}) => (
<div>
<table>
<thead>
<tr>
{cols.map((col,key) => (
<Th key={key} onClickSort={onClickSort(col.id)}>{col.name}</Th>
)}
</tr>
</thead>
<tbody>
{rows.map((row,key) => ...}
</tbody>
</table>
<button onClick={onClickNextPage}>Next Page</button>
</div>
);
const Table = connect(
({table}, {tableId}) => ({ // example: if tableId = "customers" ...
cols: table[tableId].cols, // state.table.customers.cols
rows: table[tableId].rows // state.table.customers.rows
}),
(dispatch, {tableId}) => ({
onClickSort: columnId => event => {
dispatch(actions.tableSortColumn(tableId, columnId));
// example: if user clicks 'last_name' column in customers table
// dispatch(actions.tableSortColumn('customers', 'last_name'));
},
onClickNextPage: event => {
dispatch(actions.tableNextPage(tableId))
}
})
)(_Table);
export default Table;
If you only learn one thing from this post, let it be this:
这里要注意的是 mapStateToProps 和 mapDispatchToProps accepts a second argument称为 ownProps。
// did you know you can pass a second arg to these functions ?
const MyContainer = connect({
(state, ownProps) => ...
(dispatch, ownProps) => ...
})(...);
在我上面写的容器中,我正在解构我们关心的每个变量。
// Remember how I used the container ?
// here ownProps = {tableId: "customers"}
<Table tableId="customers" />
现在看看我是如何使用connect
const Table = connect(
// mapStateToProps
({table}, {tableId}) => ...
// table = state.table
// tableId = ownProps.tableId = "customers"
// mapDispatchToProps
(dispatch, {tableId}) => ...
// dispatch = dispatch
// tableId = ownProps.tableId = "customers"
)(_Table);
这样,当我们为底层组件 (_Table) 创建调度处理程序时,我们将在处理程序中获得可用的 tableId。如果您不希望 _Table 组件本身甚至不必关心 tableId 属性,这实际上有点不错。
接下来注意 onClickSort 函数的定义方式。
onClickSort: columnId => event => {
dispatch(actions.tableSortColumn(tableId, columnId));
}
_Table 组件将此函数传递给 Th 使用
<Th key={key} onClickSort={onClickSort(col.id)}>{col.name}</Th>
看看它如何仅将columnId 发送到此处的处理程序?接下来,我们将了解 Th 是如何发送 event 的,它最终会调度 action。
组件/表/Th.js
import React from 'react';
const Th = ({onClickSort, children}) => (
<th>
<a href="#sort" onClickSort={event => {
event.preventDefault();
onClickSort(event);
}}>{children}</a>
</th>
);
export default Th;
如果您不需要 event,则没有必要保留它,但我想我会向您展示如何附加它,以防您想将其用于某些用途。
继续...
actions/index.js
您的操作文件将看起来非常标准。请注意,我们在每个表操作中提供了对 tableId 的访问。
export const TABLE_SORT_COLUMN = 'TABLE_SORT_COLUMN';
export const TABLE_NEXT_PAGE = 'TABLE_NEXT_PAGE';
export const tableSortColumn = (tableId, columnId) => ({
type: TABLE_SORT_COLUMN, payload: {tableId, columnId}
});
export const tableNextPage = (tableId) => ({
type: TABLE_NEXT_PAGE, payload: {tableId}
});
...
最后,您的 tableReducer 可能看起来像这样。同样,这里没有什么特别的。您将对操作类型执行常规 切换,然后相应地更新状态。您可以使用 action.payload.tableId 影响状态的适当部分。请记住我提出的状态形状。如果您选择不同的状态形状,则必须更改此代码以匹配
const defaultState = {
customers: {
page: 0,
sortBy: null,
cols: [],
rows: []
}
};
// deep object assignment for nested objects
const tableAssign = (state, tableId, data) =>
Object.assign({}, state, {
[tableId]: Object.assign({}, state[tableId], data)
});
const tableReducer = (state=defaultState, {type, payload}) => {
switch (type) {
case TABLE_SORT_COLUMN:
return tableAssign(state, payload.tableId, {
sortBy: payload.columnId
});
case TABLE_NEXT_PAGE:
return tableAssign(state, payload.tableId, {
page: state[payload.tableId].page + 1
});
default:
return state;
}
};
备注:
我不打算讨论表数据的异步加载。这样的工作流程已经在 redux 文档中得到了很好的详细说明:Async Actions .您可以选择 redux-thunk、redux-promise 或 redux-saga。选择你最了解的!正确实现 TABLE_DATA_FETCH 的关键是确保像我在其他 onClick* 中那样发送 tableId(以及您需要的任何其他参数) > 处理程序。
关于javascript - react redux 架构表操作和缩减器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35841558/
我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption
我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?
在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.
我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的
a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],
我有一个非常简单的Controller来管理我的Rails应用程序中的静态页面:classPagesController我怎样才能让View模板返回它自己的名字,这样我就可以做这样的事情:#pricing.html.erb#-->"Pricing"感谢您的帮助。 最佳答案 4.3RoutingParametersTheparamshashwillalwayscontainthe:controllerand:actionkeys,butyoushouldusethemethodscontroller_nameandaction_nam
我是一名决定学习Ruby和RubyonRails的ASP.NETMVC开发人员。我已经有所了解并在RoR上创建了一个网站。在ASP.NETMVC上开发,我一直使用三层架构:数据层、业务层和UI(或表示)层。尝试在RubyonRails应用程序中使用这种方法,我发现没有关于它的信息(或者也许我只是找不到它?)。也许有人可以建议我如何在RubyonRails上创建或使用三层架构?附言我使用ruby1.9.3和RubyonRails3.2.3。 最佳答案 我建议在制作RoR应用程序时遵循RubyonRails(RoR)风格。Rails
我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan
1、接口请求基本操作1.1例子tips在view的选项可以zoomin调整窗口字帖大小。1、创建一个测试的workspace,并命名为test2、test后面新增一个addrequest3、选择发送GET,URL为一个开源的https://api.apiopen.top/api/sentences获取每日一句4、点击send查看内容Tips:如果提示出现Error:tunnelingsocketcouldnotbeestablished,statusCode=407错误,参照以下解决办法)关于tunnelingsocketcouldnotbeestablished,cause=getaddri
Linux操作系统——网络配置与SSH远程安装完VMware与系统后,需要进行网络配置。第一个目标为进行SSH连接,可以从本机到VMware进行文件传送,首先需要进行网络配置。1.下载远程软件首先需要先下载安装一款远程软件:FinalShell或者xhell7FinalShellxhell7FinalShell下载:Windows下载http://www.hostbuf.com/downloads/finalshell_install.exemacOS下载http://www.hostbuf.com/downloads/finalshell_install.pkg2.配置CentOS网络安装好