gpt4 book ai didi

javascript - 可编辑 react 表: pass data between components

转载 作者:行者123 更新时间:2023-12-02 21:38:54 25 4
gpt4 key购买 nike

好吧,我是 React 新手,需要帮助读取/引用 HTML 元素数据属性,甚至 HTML 标记中的内容 - 通常使用纯 JS(这就是我在 React 应用程序中所做的)我读像这样:

const postRow = document.getElementById(tableRowId);
;
const author = postRow.getElementsByTagName('td')[0].getAttribute('data-fieldvalue');
const title = postRow.getElementsByTagName('td')[1].getAttribute('data-fieldvalue');
const description = postRow.getElementsByTagName('td')[2].getAttribute('data-fieldvalue');

我有一个名为 Table 的功能组件,我这样使用:

        <Table
headers={this.state.postsHeaders}
rows={this.state.posts}
editable={this.state.editable}
deletable={this.state.deletable}
onUpdateIconClicked={this.toggleUpdatePostModalView}
onDeleteIconClicked={this.toggleDeletePostModalView}
/>

其中 rows 属性是我使用 axios 检索的数据。我的表生成了包含多个 tr > td 行的 find 。我为每一行都有一个“编辑”CTA,单击它会打开一个模式,在其中传递要为每一行编辑的数据。 CTA 的 Onclick 调用这个函数,效果很好:

    toggleUpdatePostModalView = (postId, tableRowId) => {
// toggle the confirm delete post view
let showUpdatePostModal = !this.state.showUpdatePostModal;
// when postId and tableRowId are both null that means
// that the view delete confirm modal must remain not
// visible (closed) so have to override the toggle
if (postId === null && tableRowId === null) {
showUpdatePostModal = false;
}

const postRow = document.getElementById(tableRowId);
;
const author = postRow.getElementsByTagName('td')[0].getAttribute('data-fieldvalue');
const title = postRow.getElementsByTagName('td')[1].getAttribute('data-fieldvalue');
const description = postRow.getElementsByTagName('td')[2].getAttribute('data-fieldvalue');
// dont get the elements directly like above https://reactjs.org/docs/refs-and-the-dom.html

this.setState({
...this.state,
showUpdatePostModal: showUpdatePostModal,
postToUpdate: {
postId: postId,
tableRowId: tableRowId,
author: author,
title: title,
description: description
}
});
}

有人指出的问题是我不应该使用 JS 方式获取数据(getElementByIdgetElementsByTagName 函数,因为虚拟 DOM 和真实 DOM 同步所以我被指向 https://reactjs.org/docs/refs-and-the-dom.html 但如果我的 tr 本身是一个组件,这似乎可以工作,但事实上,它只是我的 Table 渲染函数中的 HTML,如下所示:

const table = (props) => {

// the following code creates an array from props.header object
// that is an indexed array (0, 1, ..., n) and each value
// contains the key properties that compose object props.header,
// and so, even though in .map() the parameter says 'key'
// this is misleading because in reality it is the VALUE
// (since the key of the array is 0 or 1 or n) but it is called
// 'key' because it is the key in the props.headers object that we
// need to get the info for (.map(function(currentValue, index, arr))
const headersArray = Object.keys(props.headers);
const tableHeaders = headersArray.map(key => {
return <th key={key}>{props.headers[key]}</th>;
});
const editHeader = props.editable === true ? <th key="edit">Edit</th> : null;
const deleteHeader = props.deletable === true ? <th key="delete">Delete</th> : null;

let tableRows = null;
if (props.rows) {

tableRows = props.rows.map((row, key) => {

return (
<tr id={`tr-${key}`} key={key}>
{/* inner loop to dynamically generate the <td>
depending on how many headers there are since
each header corresponds to a key or column in
the table */}
{headersArray.map(tdKey => {
return <td key={tdKey} data-fieldname={tdKey} data-fieldvalue={row[tdKey]} >{row[tdKey]}</td>
})}

{props.editable === true ? <td key="edit"><PencilIcon onClick={() => props.onUpdateIconClicked(row.postId, `tr-${key}`)} /></td> : null}
{props.deletable === true ? <td className="delete-icon-container" key="delete"><TrashIcon onClick={() => props.onDeleteIconClicked(row.postId, `tr-${key}`)} /></td> : null}
</tr>
);

});

}

return (

<table className="table is-striped">
<thead>
<tr>
{tableHeaders}
{editHeader}
{deleteHeader}
</tr>
</thead>

<tbody>
{tableRows}
</tbody>
</table>

);

}

我还了解到这些引用不应该经常使用 - 那么如果我有一个包含 100 行的表怎么办? 200?我不知道如何继续并以 React 方式执行此操作...任何人都可以帮忙吗?

最佳答案

引用号是NOT 一个适合在这里使用的工具。

相反,你应该这样做lifting state up (很多)。

为了做到这一点,我建议

  • 将表组件分解为共同父级 <Header /> 内的较小部分(例如 <Row /><App /> 等)和一个单独的 <EditDialog />/<DeleteDialog />编辑/删除行数据的组件)-较小的组件更易于维护和故障排除
  • 将表数据(最好是具有唯一记录 id )存储在父组件 ( <Table /> ) 中,并将与表行相对应的数据条目作为参数传递给 <Row />组件
  • 传递摘要onEdit()onDelete()事件处理程序作为<Row />的 Prop 组件并将其附加到 onClick() 编辑/删除按钮的处理程序
  • 将这些子属性( onEdit()onDelete() )绑定(bind)到父级中将触发编辑/删除对话框的回调
  • 记录编辑/删除后更新 <Table /> 的状态相应地。

这是上述内容的完整演示(我使用 MaterialUI 进行样式设置,以免使用大量 CSS 使演示负担过重,您可以继续使用自定义组件,希望这不会成为我的示例您不太清楚):

const { useState } = React,
{ render } = ReactDOM,
{ TableContainer, Table, TableHead, TableBody, TableRow, TableCell, IconButton, Dialog, DialogTitle, DialogContent, DialogContentText, Button, TextField, FormGroup } = MaterialUI

const srcData = [{id:0, author: 'Author1', title: 'Post 1', description: 'Some description'},{id:1, author: 'Author2', title: 'Post 2', description: 'Some other description'},{id:2, author: 'Author3', title: 'Post 3', description: 'Something else'}],
dataFields = [{id: 0, title: 'Author', key: 'author'},{id: 1, title: 'Title', key: 'title'},{id:2, title: 'Description', key: 'description'}]

const EditButton = ({handleClick}) => (
<IconButton onClick={handleClick} >
<i className="material-icons">create</i>
</IconButton>
)

const DeleteButton = ({handleClick}) => (
<IconButton onClick={handleClick} >
<i className="material-icons">delete</i>
</IconButton>
)

const DeleteDialog = ({isOpen, onDialogClose, onConfirmDelete, recordId}) => (
<Dialog open={isOpen} onClose={onDialogClose} >
<DialogTitle>Delete record</DialogTitle>
<DialogContent>
<DialogContentText>Are you sure you want to delete this record?</DialogContentText>
<FormGroup>
<Button onClick={() => onConfirmDelete(recordId)}>Yes</Button>
<Button onClick={onDialogClose}>No</Button>
</FormGroup>
</DialogContent>
</Dialog>
)

const EditDialog = ({isOpen, onDialogClose, onSubmitEdit, recordData, fields}) => {
const [data, setData] = useState(),
handleEdit = (key,value) => setData({...data, [key]:value})
return (
<Dialog open={isOpen} onClose={onDialogClose} >
<DialogTitle>Edit record</DialogTitle>
<DialogContent>
<FormGroup>
{
fields.map(({key,title}) => (
<TextField
key={key}
defaultValue={recordData[key]}
label={title}
onChange={({target:{value}}) => handleEdit(key,value)}
/>
))
}
</FormGroup>
<FormGroup>
<Button onClick={() => onSubmitEdit({...recordData,...data})}>Submit</Button>
<Button onClick={() => onDialogClose()}>Cancel</Button>
</FormGroup>
</DialogContent>
</Dialog>
)
}

const Header = ({columnTitles}) => (
<TableHead>
<TableRow>
{columnTitles.map(({title,id}) => <TableCell key={id}>{title}</TableCell>)}
<TableCell>Action</TableCell>
</TableRow>
</TableHead>
)

const Row = ({rowData, columns, onEdit, onDelete}) => (
<TableRow>
{columns.map(({key}, i) => <TableCell key={i}>{rowData[key]}</TableCell>)}
<TableCell>
<EditButton handleClick={() => onEdit(rowData.id)} />
<DeleteButton handleClick={() => onDelete(rowData.id)} />
</TableCell>
</TableRow>
)

const App = ({data,fields}) => {
const [tableData, setTableData] = useState(data),
[dataFields, setDataFields] = useState(fields),
[deleteDialogOn, setDeleteDialogOn] = useState(false),
[editDialogOn, setEditDialogOn] = useState(false),
[recordIdToDelete, setRecordIdToDelete] = useState(),
[recordIdToEdit, setRecordIdToEdit] = useState(),
onEditDialogOpen = (id) => (setRecordIdToEdit(id),setEditDialogOn(true)),
onDeleteDialogOpen = (id) => (setRecordIdToDelete(id), setDeleteDialogOn(true)),
handleEdit = (data) => {
setEditDialogOn(false)
const tableDataCopy = [...tableData],
editedItemIdx = tableDataCopy.findIndex(({id}) => id == data.id)
tableDataCopy.splice(editedItemIdx,1,data)
setTableData(tableDataCopy)
},
handleDelete = (idRecordToDelete) => {
setDeleteDialogOn(false)
const tableDataCopy = [...tableData]
setTableData(tableDataCopy.filter(({id}) => id!=recordIdToDelete))
}
return (
<div>
<DeleteDialog
isOpen={deleteDialogOn}
onDialogClose={() => setDeleteDialogOn(false)}
onConfirmDelete={handleDelete}
recordId={recordIdToDelete}
/>
<EditDialog
isOpen={editDialogOn}
onDialogClose={() => setEditDialogOn(false)}
onSubmitEdit={handleEdit}
recordData={tableData.find(({id}) => id==recordIdToEdit)||{}}
fields={dataFields}
/>
<TableContainer>
<Table>
<Header columnTitles={dataFields} />
<TableBody>
{
tableData.map(data => (
<Row
key={data.id}
rowData={data}
columns={dataFields}
onEdit={onEditDialogOpen}
onDelete={onDeleteDialogOpen}
/>
))
}
</TableBody>
</Table>
</TableContainer>
</div>
)
}

render (
<App data={srcData} fields={dataFields} />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.1/axios.min.js"></script><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"><div id="root"></div>

关于javascript - 可编辑 react 表: pass data between components,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60419278/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com