PL
React - jak stworzyć edytowalną tabelę
0
points
W tym krótkim artykule chcielibyśmy pokazać, jak stworzyć prostą edytowalną tabelę w Reakcie.
Uwaga:
Przejdź do tego artykułu, aby zobaczyć przykład edytowalnej komórki tabeli.
Praktyczny przykład:
// ONLINE-RUNNER:browser;
// Uwaga: Odkomentuj poniższe linijki podczas pracy z kompilatorem JSX:
// import React from 'react';
// import ReactDOM from 'react-dom';
// Komórka -----------------------------------------
const itemStyle = {
padding: '2px',
border: '1px solid silver',
fontFamily: 'Arial',
fontSize: '13px',
display: 'flex'
};
const textStyle = {
...itemStyle,
padding: '5px 4px',
height: '16px'
};
const inputStyle = {
padding: '0',
flex: '1',
width: '100%',
minWidth: '20px',
fontFamily: 'Arial',
fontSize: '13px'
};
const buttonStyle = {
flex: 'none'
};
const Cell = React.memo(({value, mode, onChange}) => {
const [localMode, setLocalMode] = React.useState(mode ?? 'read');
const [localValue, setLocalValue] = React.useState(value ?? '');
React.useEffect(() => setLocalMode(mode ?? 'read'), [mode]);
React.useEffect(() => setLocalValue(value ?? ''), [value]);
if (localMode === 'edit') {
const handleInputChange = (e) => setLocalValue(e.target.value);
const handleSaveClick = () => {
setLocalMode('read');
onChange?.(localValue);
};
return (
<div style={itemStyle}>
<input type="text"
value={localValue}
style={inputStyle}
onChange={handleInputChange} />
<button style={buttonStyle} onClick={handleSaveClick}>Ok</button>
</div>
);
}
if (localMode === 'read') {
const handleEditClick = () => {
setLocalMode('edit');
};
return (
<div style={textStyle} onClick={handleEditClick}>{localValue}</div>
);
}
return null;
});
// Wiersz ------------------------------------------
const tdStyle = {
padding: '1px',
border: '1px solid black',
};
const optionStyle = {
...tdStyle,
width: '30px'
};
const Row = React.memo(({ mode, columns, data, onChange, onDelete}) => {
const handleDeleteClick = () => onDelete?.();
return (
<tr>
{columns.map(({path}, columnIndex) => {
const handleChange = value => {
if (onChange) {
const changedData = { ...data, [path]: value };
onChange(columnIndex, changedData);
}
};
return (
<td key={path} style={tdStyle}>
<Cell
mode={mode}
value={data[path]}
onChange={handleChange}
/>
</td>
);
})}
<td style={optionStyle}>
<button onClick={handleDeleteClick}>Usuń</button>
</td>
</tr>
);
});
// TABELA ----------------------------------------
const tableStyle = {
border: '1px solid black',
borderCollapse: 'collapse',
width: '100%'
}
const Table = React.memo(({id, columns, data, onAdd, onChange, onDelete}) => {
const [addedIndex, setAddedIndex] = React.useState();
const handleAddClick = () => {
onAdd?.(data.length);
setAddedIndex(data.length);
};
return (
<div>
<table style={tableStyle}>
<tbody>
<tr>
{columns.map(({path, name}) => (
<th key={path} style={tdStyle}>{name}</th>
))}
</tr>
{data.map((rowData, rowIndex) => {
const handleChange = (columnIndex, changedData) => {
onChange?.(rowIndex, columnIndex, changedData);
};
const handleDelete = () => {
if (rowIndex !== addedIndex) {
setAddedIndex(addedIndex - 1);
}
onDelete?.(rowIndex, rowData);
};
return (
<Row
key={rowData[id]}
mode={addedIndex === rowIndex ? 'edit' : 'read'}
columns={columns}
data={rowData}
onChange={handleChange}
onDelete={handleDelete}
/>
);
})}
</tbody>
</table>
<br />
<div>
<button onClick={handleAddClick}>Dodaj wiersz</button>
</div>
</div>
);
});
// PRZYKŁAD --------------------------------------
const columns = [
{ path: 'id', name: 'ID' },
{ path: 'name', name: 'Imię' },
{ path: 'age', name: 'Wiek' }
];
let counter = 0;
const App = () => {
const [data, setData] = React.useState(() => ([
{ id: ++counter, name: 'Bartek', age: 22 },
{ id: ++counter, name: 'Adam', age: 43 },
{ id: ++counter, name: 'Marek', age: 16 },
{ id: ++counter, name: 'Jacek', age: 29 }
]));
const handleAdd = (rowIndex) => {
const newRowData = { id: ++counter };
setData([ ...data, newRowData ]);
//TODO: żądanie AJAX do serwera
console.log(`Dodano pusty wiersz!`);
};
const handleChange = (rowIndex, columnIndex, changedRowData) => {
const columnData = columns[columnIndex];
const changedRowJson = JSON.stringify(changedRowData, null, 4);
//TODO: żądanie AJAX do serwera
console.log(`Changed row:\n${changedRowJson}`);
};
const handleDelete = (rowIndex, removedRowData) => {
setData(data.filter((value, index) => index !== rowIndex));
//TODO: żądanie AJAX do serwera
console.log(`Usunięto wiersz: ${rowIndex}`);
};
return (
<div>
<Table
id="id"
columns={columns}
data={data}
onAdd={handleAdd}
onChange={handleChange}
onDelete={handleDelete}
/>
</div >
);
};
const root = document.querySelector('#root');
ReactDOM.render(<App/>, root );