0

I am looking for some help with conditional rendering inside of the return of my ReactJS page.

Here is what my code looks like:

import React from "react";

import NoActiveTracker from "../components/NoActiveTracker.js";
import NoCompletedTracker from "../components/NoCompletedTracker.js";


var bg = {
  background: "#6F42C1"
}

class TrackerGeneralPage extends React.Component {
    state = {
        id: '',
        active: [],
        completed: [],
        completedDateNow: '',
        newStatus: 'Complete'
      };      

  render() {
    const { active, completed } = this.state

    // if this.state.active.length > 0 ? { ---- I can do this with the return and set an else that will work fine but I am trying to do it for each table
    return (
        <>
        <div>

          {/* Active Trackers */}
          <div id="toggle-active" className="">
            <div className="my-4">
              <table className="table table-hover table-bordered mb-3">
                <thead className="thead-dark">
                  <tr>
                    <th scope="col" className="h5">Active</th>
                    <th scope="col">Name</th>
                    <th scope="col">Regulation</th>
                    <th scope="col">Due On</th>
                    <th scope="col">Assigned</th>
                    <th scope="col">Status</th>
                  </tr>
                </thead>
                <tbody>
                {/* Need to perform conditional rending here with <NoActiveTrackers /> */}
                {active.map(item => (
                    <>
                    <tr key={item.id}>
                      <th scope="row" className="dropdown">
                        <a className="btn btn-dark" data-toggle="collapse" href={"#a" + item.id} role="button" aria-expanded="false" aria-controls="item">Expand</a>
                      </th>
                      <td>{item.name}</td>
                      <td>{item.reg}</td>
                      <td>{item.dateDue}</td>
                      <td>{item.assigned}</td>
                      <td>{item.status}</td>
                    </tr>
                      <tr>
                        <td id={"a" + item.id} className="collapse hiddenRow" colSpan="6" rowSpan="1">
                          <div class="row">
                            <div class="col-sm">
                              <div class="card text-white text-center" style={bg}>
                                <div class="card-body">
                                  <h5 class="card-title text-white font-weight-bold">Occurrence</h5>
                                  <p class="card-text">{item.occurrence}</p>
                                  <p>Next Expected Occurrence: Unknown</p>
                                  </div>
                              </div>
                            </div>
                            <div class="col-sm">
                              <div class="card bg-light text-center">
                                <div class="card-body">
                                  <h5 class="card-title font-weight-bold">Completed By</h5>
                                  <p class="card-text">{item.completer} on {item.dateCompleted}</p>
                                  <button className="btn btn-dark" onClick={() => this.handleUpdateTracker(item)} >Mark as Complete <img src="https://icon.now.sh/done_all/ffffff" width="25" height="25" className="d-inline-block align-top" alt="Complete Tracker" /></button>
                                </div>
                              </div>
                            </div>
                            <div class="col-sm">
                              <div class="card text-center">
                                <div class="card-body text-white bg-dark">
                                  <h5 class="card-title text-white font-weight-bold">Description</h5>
                                  <p class="card-text">{item.description}</p>
                                  <button className="btn btn-light ml-1" onClick={() => this.handleDeleteTracker(item.id)} >Delete Tracker<img src="https://icon.now.sh/delete_forever" width="25" height="25" className="d-inline-block align-top" alt="Delete Tracker" /></button>
                                </div>
                              </div>
                            </div>
                          </div>
                        </td>
                    </tr>
                  </>
                ))}
                 </tbody>
              </table>
            </div> {/* End Table Section */}
          </div> {/* End Active Toggle */}


          {/* Completed Trackers */}
          <div id="toggle-active" className="">
            <div className="my-4">
              <table className="table table-hover table-bordered mb-3">
                <thead className="thead-dark">
                  <tr>
                    <th scope="col" className="h5">Completed</th>
                    <th scope="col">Name</th>
                    <th scope="col">Regulation</th>
                    <th scope="col">Due On</th>
                    <th scope="col">Assigned</th>
                    <th scope="col">Status</th>
                  </tr>
                </thead>
                <tbody>
                {/* Need to perform conditional rending here with <NoCompleteTrackers /> */}
                {completed.map(item => (
                    <>
                    <tr key={item.id}>
                      <th scope="row" className="dropdown">
                        <a className="btn btn-dark" data-toggle="collapse" href={"#a" + item.id} role="button" aria-expanded="false" aria-controls="item">Expand</a>
                      </th>
                      <td>{item.name}</td>
                      <td>{item.reg}</td>
                      <td>{item.dateDue}</td>
                      <td>{item.assigned}</td>
                      <td>{item.status}</td>
                    </tr>
                      <tr>
                        <td id={"a" + item.id} className="collapse hiddenRow" colSpan="6" rowSpan="1">
                          <div class="row">
                            <div class="col-sm">
                              <div class="card text-white text-center" style={bg}>
                                <div class="card-body">
                                  <h5 class="card-title text-white font-weight-bold">Occurrence</h5>
                                  <p class="card-text">{item.occurrence}</p>
                                  </div>
                              </div>
                            </div>
                            <div class="col-sm">
                              <div class="card bg-light text-center">
                                <div class="card-body">
                                  <h5 class="card-title font-weight-bold">Completed By</h5>
                                  <p class="card-text">{item.completer} on {item.dateCompleted}</p>
                                </div>
                              </div>
                            </div>
                            <div class="col-sm">
                              <div class="card text-center">
                                <div class="card-body text-white bg-dark">
                                  <h5 class="card-title text-white font-weight-bold">Description</h5>
                                  <p class="card-text">{item.description}</p>
                                </div>
                              </div>
                            </div>
                          </div>
                        </td>
                    </tr>
                  </>
                ))}
                 </tbody>
              </table>
            </div> {/* End Table Section */}
          </div> {/* End Completed Toggle */}

        {/* Conditional Rendering Components are here just so I can visually seem them at the bottom of the page no matter way, will be removed once I figure out the conditional rendering of them */}
          <NoActiveTracker />
          <NoCompletedTracker />

        </div> {/* End Container */}
        </>
    )
  }
}

export default TrackerGeneralPage;

I can do if this.state.active.length > 0 ? { with the entire return ( and an else after that contains one of my components like NoActiveTrackers but since I have two tables, that means I would need a 4x if statement: one return if both trackers had items, one return if active had items but completed did not, one return if completed had items but active did not, and one return if both trackers did not have items.

How can I do conditional rendering directly before the map(s)?

Regards

2 Answers 2

1

Because you have 2 cases that have the same logic for displaying components, you can abstract this logic into a different component, for eg. a List component that takes your ListItem and NoItems as a prop and renders it.

const { render } = ReactDOM;

function Active() {
  return <p>Definition of an active List item here</p>
}

function Completed() {
  return <p>Definition of an active Completed item here</p>
}

function NoActive() {
  return <p>No active list items to see here</p>
}

function NoCompleted() {
  return <p>No completed list items to see here</p>
}

function List({
  array,
  listItem: ListItem, /*has start with capital letter */
  noItems: NoItems,
}) {
  if(array.length) {
    return array.map((item, index) => <ListItem key={index} />);
  } else {
    return <NoItems />
  }
}

function App() {
  const activeItems = [1, 2];
  const completedItems = [];
  return (
    <main>
      <List array={activeItems} listItem={Active} noItems={NoActive} />
      <List array={completedItems} listItem={Completed} noItems={NoCompleted} />
    </main>
  )
}

render(<App />, document.getElementById("root"))
<div id="root" />
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

Sign up to request clarification or add additional context in comments.

4 Comments

this seems to work fine except for it places the return(s) inside of the table's first column only instead of spread across all of them as it was previously. How it was , How it is after implementing your solution, new code is here
@Matthew looks like you got one of the rows or columns in the wrong place
ah, I added an extra Div tag on the functions instead of just a fragment like <>. Thanks for your help!
Just noticed but this causes my items to double once two or more are added. Any idea what may be causing it? Here is my code and here is a visual. If I remove this within the visual, it says item is no longer defined.
0

I think you are looking for something like this. active.length &&.
If active array is empty, active.map will not be run here.

                {/* Need to perform conditional rending here with <NoActiveTrackers /> */}
                {active.length && active.map(item => ( ...

3 Comments

How would I show the placeholder if its empty with this?
@Matthew You could add another block with { !active.length && ...
After implementing this, it works much better and only adds three lines of code (which can be placed inside of one line) instead of multiple with the other answer! Thank you! Keep the original maps like so: ``` {active.map(item => ( ... ) ``` But add this directly after: ``` {/* Only renders if active array has zero items */} { !active.length && ( <NoActiveTracker /> )} ```

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.