当前位置: 首页 > 面试题库 >

可编辑的React表:在组件之间传递数据

淳于知
2023-03-14
问题内容

好的,我是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行的查找。单击后,我为每一行都有一个“编辑”
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方式执行此操作…任何人都可以帮忙吗?


问题答案:

裁判是 不是 在这里使用合适的工具。

相反,您应该提升状态( 很多 )。

为此,我建议

  • 将您的表组件分解为较小的部分(例如<Header /><Row />等),并在公共父级中将其拆分<App />为单独的<EditDialog />/ <DeleteDialog />组件以编辑/删除行数据)-较小的组件更易于维护和解决
  • 将表数据(最好是具有唯一记录id的表)存储在parent(<Table />)组件中,并将与表行相对应的数据条目作为参数传递给<Row />组件
  • 将抽象onEdit()onDelete()事件处理程序作为道具传递给<Row />组件,并将其附加到/ 按钮的onClick()处理程序Edit``Delete
  • 将那些子道具(onEdit()onDelete())绑定到父项中的回调,这将触发编辑/删除对话框
  • 在记录编辑/删除相应的更新状态时<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(recordData),

        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>


 类似资料:
  • 问题内容: 我对React和Redux非常陌生,我正在尝试将数据从一个组件传递到另一个组件。但它没有父子关系,并且彼此独立。谁能帮我做到这一点?下面是我的代码。 另一个文件是我想发送EmpNumber的位置, 问题答案: 好的,这是一个例子。我将假设您已经配置了所有Redux存储,即创建存储,rootReducer等…,因为这是一个单独的帖子。 因此,基本的想法是,当你想更新你的终极版商店状态你

  • 问题内容: 我有一个调用会弹出一个的,以便用户可以选择目录。这些都是单独的类。从中传递值的正确方法是什么,以便我可以在中显示目录的路径? 编辑:更新了问题。 问题答案: 这是一个不完整的示例,但我想可以使您了解如何实现所需的目标。重要的一点是引用要在其中进行选择的属性,例如 参见下面如何将其放置在代码中: 希望对您有所帮助,对不起您没有提供完整的示例。 编辑 本质上,我们没有将任何参数传递给Abs

  • 我的Navbar组件有2个子组件。每个组件都有自己的状态。在其组成部分内工作正常的国家。如何更新这两个状态从假到真的同时,当两个功能onclick将被执行? 主组件导航栏 列表菜单组件 汉堡包成分

  • 本文向大家介绍vue.js组件之间传递数据的方法,包括了vue.js组件之间传递数据的方法的使用技巧和注意事项,需要的朋友参考一下 前言 组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。如何传递数据也成了组件的重要知识点之一。 组件 组件与组件之间,还存在着不同的关系。父子关系与兄弟关系(不是父子的都暂称为兄弟吧)。 父子组件 父子

  • 本文向大家介绍react 父组件与子组件之间的值传递的方法,包括了react 父组件与子组件之间的值传递的方法的使用技巧和注意事项,需要的朋友参考一下 概念上,组件是封闭的环境。React中是单向数据流的设计,也就是是说只有父组件传递资料给子组件这回事。以正确的技术说明,拥有者组件可以设置被拥有者组件中的数据。 那么子组件要如何与父组件沟通这件事,简单的来说,是一种迂回的作法,在父组件中设置了一个

  • 简而言之,我需要一个“购物车”一样的关系,从一个组件到网站的其余部分。我说“类似购物车”是因为它基本上是用户浏览时产生的需求列表。它不会有任何价格或税收逻辑,但每种类型的需求都有其“自己的< code >子参数,与我正在为其创建< code >接口的其他需求不同。我认为< code >需求组件将使用< code>any类型来接受输入的数据块。 截至目前,创建@Inputs和穿过整个树的大规模高速公