#javascript #reactjs #data-binding
#javascript #reactjs #привязка к данным
Вопрос:
Я не могу повторно отобразить свою сетку после изменения hidden
состояния столбца. Я думал, что изменение columns
приведет к повторному отображению сетки, поскольку это связанный атрибут.
Вот интерактивный пример, размещенный на codesandbox.io .
index.jsx
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
App.js
import React from "react";
import SuperTable from "./components/SuperTable";
const data = [
{ id: 1, type: "Developer", name: "Bob", age: 21 },
{ id: 2, type: "Developer", name: "Mary", age: 28 },
{ id: 3, type: "Manager", name: "Steve", age: 42 }
];
const columns = [
{
field: "id",
title: "ID",
searchable: true,
hidden: true
},
{
field: "name",
title: "Name",
searchable: true
},
{
field: "age",
title: "Age",
searchable: true
},
{
field: "type",
title: "Type",
searchable: true
}
];
const App = () => {
return <SuperTable data={data} columns={columns} />;
};
export default App;
SuperTable.jsx
import MaterialTable from "material-table";
import React, { forwardRef } from "react";
import { makeStyles } from "@material-ui/core/styles";
import ArrowDownward from "@material-ui/icons/ArrowDownward";
import ChevronLeft from "@material-ui/icons/ChevronLeft";
import ChevronRight from "@material-ui/icons/ChevronRight";
import ClearIcon from "@material-ui/icons/Clear";
import FirstPage from "@material-ui/icons/FirstPage";
import LastPage from "@material-ui/icons/LastPage";
import Search from "@material-ui/icons/Search";
import ColumnToggler from "./ColumnToggler";
const useStyles = makeStyles((theme) => ({
wrapper: {
display: "flex",
flexDirection: "row"
},
widget: {
display: "flex",
flexDirection: "column",
flex: 0.5
}
}));
const tableIcons = {
ResetSearch: forwardRef((props, ref) => <ClearIcon {...props} ref={ref} />),
FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
PreviousPage: forwardRef((props, ref) => (
<ChevronLeft {...props} ref={ref} />
)),
Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
SortArrow: forwardRef((props, ref) => <ArrowDownward {...props} ref={ref} />)
};
const SuperTable = (props) => {
const { data, columns, ...rest } = props;
const classes = useStyles();
const onToggle = (columnField, show) => {
const foundColumn = columns.find((col) => col.field === columnField);
if (foundColumn) {
foundColumn.hidden = show;
}
};
return (
<div className={classes.wrapper}>
<MaterialTable
style={{
position: "unset",
display: "flex",
flexDirection: "column",
flex: 1
}}
title={null}
data={data}
columns={columns}
icons={tableIcons}
pageSize={5}
{...rest}
/>
<div className={classes.widget}>
<ColumnToggler onChange={onToggle} columns={columns} />
</div>
</div>
);
};
SuperTable.propTypes = {
...MaterialTable.propTypes
};
export default SuperTable;
ColumnToggler.jsx
import React from "react";
import { Typography } from "@material-ui/core";
import PropTypes from "prop-types";
import { Container, makeStyles } from "@material-ui/core";
import ColumnToggleSwitch from "./ColumnToggleSwitch";
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 200
}
}));
const ColumnToggler = (props) => {
const { columns, onChange } = props;
const classes = useStyles();
const toggleChecked = (field, show) => {
onChange(field, show);
};
console.log("Updated toggler...");
return (
<Container className={classes.formControl}>
<Typography>Toggle Columns</Typography>
{columns.map((column) => (
<ColumnToggleSwitch column={column} onChange={toggleChecked} />
))}
</Container>
);
};
ColumnToggler.propTypes = {
onChange: PropTypes.func.isRequired
};
export default ColumnToggler;
Columntoggles Switch.jsx
import React, { useState } from "react";
import PropTypes from "prop-types";
import { FormControlLabel, FormGroup, Switch } from "@material-ui/core";
const ColumnToggleSwitch = (props) => {
const {
column: { field, hidden, title },
onChange
} = props;
const [checked, setChecked] = useState(hidden == null || !hidden);
const handleChange = (event, newValue) => {
setChecked(newValue);
onChange(event.currentTarget.name, newValue);
};
return (
<FormGroup>
<FormControlLabel
control={
<Switch
key={field}
name={field}
checked={checked}
onChange={handleChange}
color="primary"
inputProps={{ "aria-label": "primary checkbox" }}
size="small"
/>
}
label={title || field}
/>
</FormGroup>
);
};
ColumnToggleSwitch.propTypes = {
column: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired
};
export default ColumnToggleSwitch;
package.json
{
"dependencies": {
"@material-ui/core": "4.11.2",
"@material-ui/icons": "4.11.2",
"material-table": "1.69.2",
"react": "17.0.0",
"react-dom": "17.0.0",
"react-scripts": "3.4.3"
}
}
Ответ №1:
Основная проблема заключается в том, что реквизиты React неизменяемы. Если вы измените prop в своем компоненте, значение не будет гарантировать повторный рендеринг.
Вы изменяете свой columns
prop в своем SuperTable
компоненте, и это не может работать должным образом.
Решение состоит в том, чтобы определить столбцы как константу, импортировать ее и установить в качестве начального состояния вашего columns
состояния. columns
в любом случае это константа, и ее не нужно отправлять как реквизит.
components/columns.js
:
// define columns and export it
SuperTable.jsx
:
import initialColumns from './columns';
...
const [columns, setColumns] = useState(initialColumns);
Состояния также неизменяемы, поэтому вам не следует делать:
foundColumn.hidden = show;
но вместо этого следует сделать:
const newColumns = ....;
setColumns(newColumns);
Комментарии:
1. Я заметил, что если я пытаюсь отобразить скрытый столбец, в консоли выдается ошибка. Я понял, что данные столбца для скрытого столбца не имеют назначенной расчетной ширины. Я просто создал свои собственные ширины, и это работает. Это лучший способ сделать это? Смотрите мой обновленный (рабочий) пример. Кроме того, столбцы в конечном итоге будут динамическими, поэтому константа не будет работать … Переключение столбцов таблицы Material UI 2.0