Reactのマテリアルテーブルがあります。列の1つをカスタム<DatePicker/>
コンポーネントにして、ユーザーが行にスケジュールされた日付を割り当てることができるようにします。currentleyテーブルはデータをリモートで取得します。
ときに<DatePicker/>
コンポーネントが使用され、日付が選択されて、私はリモートソースからの再フェッチデータにテーブル全体を望んでいません。代わりに、<DatePicker/>
onChangeハンドラーで、テーブル内の現在のデータ(日付を設定している行)を変更する必要があります。
マテリアルテーブルのデータストアを利用して「setData」関数を呼び出し、ターゲット行のみを更新できるようにする方法はありますか?
通常、テーブルのデータがリモートソースからのものでない場合は、独自の「setData」関数を呼び出すだけですが、リモートデータオプションに組み込まれているマテリアルテーブルを利用しており、フィルターを使用しているため、これを行うことはできません。
マテリアルテーブルのデータを利用して、データがリモートソースからのものである場合に行を更新するための、クリーンな方法を見つけることができませんでした。しかし、私はうまくいくやや「ハッキー」な解決策を思いつくことができました。
これを達成するために、私は次のことを行いました。
data
MaterialTableのpropをカスタムgetData
関数に設定します。これはPromiseを返すか、バックエンドAPIをヒットしてテーブルデータ(すべての行)を取得するか、現在のテーブルデータを変更してからこの新しい変更データを返します。この関数はtableRef.current.dataManager.getRenderState().data
、現在のMaterialTableデータを取得するために使用します。次に、その変更バージョンを返します(必要な場合)。rowData
MaterialTableとtableRef
Reduxストアから2つの小道具を受け取る小さなコンポーネント(NextAction)を作成し、現在のテーブルデータを変更するためにクリックされるカスタムアクションボタンを保持する列をレンダリングします。このコンポーネントは、Reduxストアに保存されているマテリアルテーブルのtableRefにもアクセスできます。このコンポーネント(最終的にはボタン)はonQueryChange()
、tableRefの関数を利用して、getData関数の呼び出しを手動で強制します。アイデアは、ボタン付きの列を持つことです。ボタンが押されると、その行の「current_state」列が変更され、テーブルデータはAPIから再レンダリングされません。
これがtableRef.current.onQueryChange()
機能するのは、ボタンがクリックされると関数が呼び出されるためです。コンポーネントの「data」propはカスタムgetData関数に設定されているため、tableRef.current.onQueryChange()
が呼び出されると、MaterialTableはdata
、MaterialTableコンポーネントに設定した関数をカスタムgetData関数に呼び出すように指示されます。
次に、このgetData関数内で、新しいクエリパラメータが古いクエリパラメータと異なるかどうかを確認します(クエリパラメータもローカル状態で保存されるため)。それらが同じである場合、getDataクエリパラメータにnextStateキーがあるかどうかを確認します。このnextStateキーは、カスタムボタンからgetDataが呼び出された場合にのみ存在します。そうである場合は、tableRefを使用して現在のテーブルデータにアクセスし、必要な行を変更してから、新しいtableDataを返します(まだpromiseにラップされています)。
上記を実現するサンプルコードを次に示します。
import React, { useContext } from 'react';
import { connect } from 'react-redux';
import axios from 'my/path/to/axios';
/*
Custom Button rendered in a column on the MaterialTable
Takes a tableRef prop from the Redux Store.
Note the onClick function that is called.
*/
const NextActionButton = connect(mapStateToPropsNextAction)(( props ) => {
const tableRef = props.tableRef; // captured from redux store - tableRef from MaterialTable
return (
<Button
disabled={false}
variant="contained"
color="secondary"
size="large"
onClick={(e) => {tableRef.current.onQueryChange({
onNextAction: true,
nextState: 'dispatched',
row_id: props.rowData.tableData.id,
})}}
>
Dispatch
</Button>
)
})
const MyComponent = ( props ) => {
let tableRef = React.createRef() // Create the tableRef
props.setTableRef(tableRef)
// Store the query history
const [queryHist, setQueryHist] = React.useState({});
// Custom function to return the table data either via api or from the old state with modifications
const getData = (query, tableRef) => new Promise((resolve, reject) => {
const queryParams = {
filters: query.filters,
orderBy: query.orderBy,
orderDirection: query.orderDirection,
page: query.page,
pageSize: query.pageSize,
search: query.search,
}
/*
Here is the magic that allows us to update the current tableData state without hitting the api
If the query is the same as before, then just return the same table without hitting api
This occurs only when:
1.) the user types the same filter
2.) when the user wants to update a single row through the special update component in the update column
*/
if (JSON.stringify(queryHist) === JSON.stringify(queryParams)) {
// This is how we get MaterialTable's current table data. This is a list of objects, each object is a row.
let newData = tableRef.current.dataManager.getRenderState().data;
if (query.onNextAction === true) {
newData[query.row_id].current_state = query.nextState;
}
resolve({
data: newData,
page: tableRef.current.state.query.page,
totalCount: tableRef.current.state.query.totalCount,
})
}
setQueryHist(queryParams) // Store query params in the local state for future comparison
axios.get('/my_data_api', {
params: queryParams
}).then(response => {
return resolve({
data: response.data.data,
page: response.data.page,
totalCount: response.data.total_count,
})
}).catch(function (error) {
console.log(error);
})
})
const [columns] = React.useState([
{
title: "Record Id",
field: "record_id",
},
{
title: "Current State",
field: "current_state", // This is the field we will be updating with the NextActionButton
},
{
title: "Next Action",
field: "placeholder",
filtering: false,
render: (rowData) => <NextActionButton rowData={rowData}/> // Render the custom button component
},
])
return (
<MaterialTable
title="My Table Title"
tableRef={tableRef} // Assign the ref to MaterialTable
data={
(query) => getData(query, tableRef)
}
columns={columns}
options={{
filtering: true,
debounceInterval: 600,
paging: true,
pageSize: 50,
pageSizeOptions: [50, 100, 1000],
emptyRowsWhenPaging: false,
selection: true,
}}
.
.
.
/>
)
}
// Redux stuff
const mapDispatchToProps = dispatch => {
return {
setTableRef: (tableRef) => dispatch({type: 'SET_TABLE_REF', 'ref': tableRef})
.
.
.
};
};
export default connect(null, mapDispatchToProps)(Workorders);
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加