我当前正在尝试创建一个可重用的组件,该组件将从远程源中提取数据,并且如果后端上的项目发生更改,则可以根据需要更新表。这是一个简单的组件:
<React.Fragment>
<Header />
<table>
<thead>
<tr>
{columns.map(c => (
<th key={c.header}>{c.header}</th>
))}
</tr>
</thead>
<tbody>{data.map(row => children(row))}</tbody>
</table>
<Pagination />
</React.Fragment>
目标是,在我的订单页面上,我可以这样称呼它:
<DataTable
id="app/OrderPage/orders"
url="http://localhost:8081/api/orders"
columns={[
{ header: 'Name' },
{ header: 'Actions' },
]}
>
{order => (
<tr key={order.id}>
<td>{order.name}</td>
<td>
<Link to={`/admin/orders/${order.id}`}>
View
</Link>
</td>
</tr>
)}
</DataTable>
现在,我的想法是我想在多个地方重用此组件。我目前使用redux-saga进行提取,并在返回数据时更新数据表。 (当前,我正在提供一个数据表ID,然后将其传递给FETCH_DATA,LIMIT_CHANGED,SEARCH_CHANGED等,然后将其用于更新需要更改的切片部分:
function dataTableReducer(state = initialState, action) {
switch (action.type) {
case INIT: {
const { id, url, deletedItem } = action;
return state.setIn(
['tables', id],
initialTableState
.set('id', id)
.set('url', url)
.set('deletedItem', deletedItem),
);
}
case LOAD_DATA_SUCCESS:
return state.setIn(['tables', action.id, 'data'], action.data.data);
case LIMIT_CHANGED:
return state.setIn(['tables', action.id, 'limit'], action.limit);
case SEARCH_CHANGED:
return state.setIn(['tables', action.id, 'search'], action.search);
default:
return state;
}
}
我当前对DataTable组件的传奇故事:
function* getData({ id }) {
const dt = yield select(selectDataTableInstance(), { id });
const { url, limit, search, page } = dt;
const res = yield call(request, url, {
qs: {
limit,
search,
page,
},
});
yield put(loadDataSuccess(id, res));
}
// Individual exports for testing
export default function* dataTableSaga() {
yield all([
takeEvery(LOAD_DATA, getData),
takeEvery(LIMIT_CHANGED, getData),
takeLatest(SEARCH_CHANGED, getData),
]);
}
现在问题变成了,如何向该组件添加其他逻辑?例如,当一个新订单通过WebSocket传入时,我希望<DataTable />
组件将该行添加到列表顶部。问题是,我需要将其他逻辑连接到已存在的redux-saga。我最初的想法是向数据表中添加一个道具,例如deletedItem={DELETE_ORDER_SUCCESS}
,但这似乎是一个非常讨厌的解决方法。我的减速器需要遍历切片中的每个呈现的表,并检查action.type ===是否在显示表时初始化了该表。
我当前正在使用React Boilerplate。
TLDR:
答案 0 :(得分:0)
您可以具有一组用于Web套接字相关动作的化合器。假设在网络套接字上收到新订单时,您可以调度NEW_ORDER操作。
在减速器中,您可以更新现有状态以包括新订单(如果需要的话,在列表顶部)。因为应该从Redux存储中读取表数据,所以这应该触发重新渲染。
case LOAD_DATA_SUCCESS:
return state.setIn(['tables', action.id, 'data'], [action.data.data, state.getIn(['tables', 'action.id', 'data']);
对于需要执行的不同操作,您可以采取不同的操作。
答案 1 :(得分:0)
yield put(loadDataSuccess(id, res));
之后,我将在传奇中设置websocket并添加如下处理程序:
var ws = new WebSocket(wsAddress);
ws.onmessage = function (event) {
const newItem = event.data;
res = {...res, data:[newItem ,...res.data]};
yield put(loadDataSuccess(id, res));
}
,您需要将const res
更改为let res
然后在卸载组件时,应发送操作以允许关闭websocket。 (您可以保留一张以ID为键的开放式WebSocket的地图)