Search code examples
javascriptreactjssemantic-uisemantic-ui-react

ref is null - Semantic UI React Table row


I am trying to pass the ref of my Table.row into a click handler. Perhaps I want to select a row and highlight it when selected by changing the className. However it always logs null.

Attempt:

<Table.Body>
    {_.map(data, ({ Name, Version, Type, Modified }) => (
        <Table.Row
          ref={(ref) => { this.row = ref; }}
          className=""
          key={Version}
          onClick={() => this.handleClick(this.row, Name, Version, Type, Modified)}
        >
            <Table.Cell>{Name}</Table.Cell>
            <Table.Cell>{Version}</Table.Cell>
            <Table.Cell>{Type}</Table.Cell>
            <Table.Cell>{Modified}</Table.Cell>
        </Table.Row>
    ))}
</Table.Body>

handleClick(row, Name, Version, Type, Modified) {
    const me = this;
    log.info('logging row', row); //null
    log.info('logging row data', Name, Version, Type, Modified); //works
}

Does anybody know why ref is not working properly here?


Solution

  • As i mentioned in my comments, I don't see any support for refs in their docs.
    And as for your ref implementation, you are overriding this.row on each iteration.

    Anyway there is a more react'ish solution for this in my opinion.

    If you want to keep track of which rows were selected you will need an object in your state that will get updated on each click of a row, a kind of a lookup table object.

    To create such lookup table, you will need id's for each row (you can use an id from the data object or an index of the array).

    In order to be able pass down the id to the Table.Row and back up to the parent as a parameter of the onClick you can wrap the Table.Row with a class component that will handle the clicks and the data that it returns.

    For example MyRow will expect to get a rowId, a onClick event and of course the active props that we will pass down to Table.Row.

    when MyRow will get clicked, it will pass the this.props.rowId as a parameter to the parent, and the parent will update the lookup table.

    Here is a running example of this use case:

    const { Table } = semanticUIReact; // --> import { Table } from 'semantic-ui-react'
    
    const usersFromServer = [
      { name: 'john', age: 25, gender: 'male', id: 1 },
      { name: 'jane', age: 22, gender: 'female', id: 2 },
      { name: 'david', age: 31, gender: 'male', id: 3 },
      { name: 'jain', age: 29, gender: 'female', id: 4 }
    ];
    
    
    class MyRow extends React.Component {
      onClick = (e) => {
        const { onClick, rowId } = this.props;
        onClick(rowId, e);
      }
    
      render() {
        const { data, active } = this.props;
        return (
          <Table.Row onClick={this.onClick} active={active}>
            <Table.Cell>{data.name}</Table.Cell>
            <Table.Cell>{data.age}</Table.Cell>
            <Table.Cell >{data.gender}</Table.Cell>
          </Table.Row>
        );
      }
    }
    
    
    class TableExample extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          activeRows: []
        }
      }
    
      onRowClick = (id, e) => {
        const { activeRows } = this.state;
        const nextRows = {
          ...activeRows,
          [id]: !activeRows[id]
        }
        this.setState({ activeRows: nextRows });
      }
    
      render() {
        const { activeRows } = this.state;
        return (
          <Table unstackable>
            <Table.Header>
              <Table.Row>
                <Table.HeaderCell>Name</Table.HeaderCell>
                <Table.HeaderCell>Age</Table.HeaderCell>
                <Table.HeaderCell>Gender</Table.HeaderCell>
              </Table.Row>
            </Table.Header>
    
            <Table.Body>
              {
                usersFromServer.map((u) => {
                  const isActive = activeRows[u.id];
                  return (
                    <MyRow
                      active={isActive}
                      key={u.id}
                      rowId={u.id}
                      data={u}
                      onClick={this.onRowClick}
                    />
                  );
                })
              }
    
            </Table.Body>
          </Table>
        )
      }
    }
    
    ReactDOM.render(<TableExample />, document.getElementById('root'));
    <link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.9/semantic.min.css" rel="stylesheet"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/semantic-ui-react.min.js"></script>
    <div id="root"></div>