简体   繁体   中英

How to update a table data based on user inputs from 2 different components

I am a beginner in react. And I am working on a project that can render tabular data from an API, and user should be able to filter the table based on selections in the form of checkboxes. I have forms (checkboxes) in 2 different components.

I am trying to figure out what is the correct way to handle user inputs from either of the components and show the filtered data which is rendered in a different component.

I have a component that renders a "datatable" after fetching data from an API.

Table component:

import React, { useState, useEffect, useMemo } from "react"
import DataService from "./service"
import { MDBDataTable } from "mdbreact"
import { Row, Col, Card, CardBody, CardTitle, CardSubtitle } from "reactstrap"

const SampleList = props => {
  const [samples, setSamples] = useState([])

  useEffect(() => {
    retrieveSamples()
  }, [])

  const retrieveSamples = () => {
    DataService.sampleList()
      .then(response => {
        setSamples(response.data)
      })
      .catch(e => {
        console.log(e)
      })
  }
  
  const data = {
    columns: [
      {
        label: "Sample",
        field: "sample",
      },
      {
        label: "Group",
        field: "group",
      },
    ],
    rows: samples,
  }

  return (
    <React.Fragment>
      <Row>
        <Col className="col-12 pt-4">
          <Card>
            <CardBody>
              <CardTitle>Samples</CardTitle>
              <CardSubtitle className="mb-3">
                Please apply any filter to view the samples
              </CardSubtitle>

              <MDBDataTable responsive striped bordered data={data} />
            </CardBody>
          </Card>
        </Col>
      </Row>
    </React.Fragment>
  )
}

export default SampleList

and I have 2 different components that handle user inputs.

Component 1 with checkboxes:

import React, { useState } from "react"

const tissue = [
  "Flower",
  "Stem",
  "Shoot",
  "Root",
]
function TissueOptions(props) {
  const [formData, updateFormData] = useState([])

  const handleChange = event => {
    let all_checked = []
    if (event.target.checked) {
      console.log("Checked:" + event.target.value)
      updateFormData({
        ...formData,
        [event.target.id]: event.target.value.trim(),
      })
    } else {
      console.log("unchecked: " + event.target.value.trim())
      let newSelection = {}

      Object.entries(formData).forEach(([key, value]) => {
        if (value !== event.target.value.trim()) {
          newSelection[key] = value
        }
      })
      updateFormData(newSelection)
    }
  }

  const handleSubmit = event => {
    event.preventDefault()
    //  how to filter data from the table component
  }

  return (
    <>
      <form onSubmit={handleSubmit}>
        <ul>
          <p>Tissues</p>
          {tissue.map((name, index) => (
            <div className="form-check mb-3">
              <input
                className="form-check-input"
                type="checkbox"
                value={name.toLowerCase()}
                id={index + name}
                onChange={handleChange}
              />
              <label className="form-check-label" htmlFor={index + name}>
                {name}
              </label>
            </div>
          ))}
        </ul>

        
        <button>Filter</button>
      </form>
    </>
  )
}

export default TissueOptions

Component 2 with other filter options: (this is a child component of a separate unrelated component)

import React, { useState } from "react"

const genotype = ["Wild type", "Mutant", "Transgenic", "Hybrid", "Other", "ND"]
const treatment = ["Treated", "Untreated", "ND"]

function SidebarOptions(props) {
  const [formData, updateFormData] = useState([])

  const handleChange = event => {
    let all_checked = []
    if (event.target.checked) {
      console.log("Checked:" + event.target.value)
      updateFormData({
        ...formData,
        [event.target.id]: event.target.value.trim(),
      })
    } else {
      console.log("unchecked: " + event.target.value.trim())
      let newSelection = {}
      Object.entries(formData).forEach(([key, value]) => {
        if (value !== event.target.value.trim()) {
          newSelection[key] = value
        }
      })
      updateFormData(newSelection)
    }
  }

  const handleSubmit = event => {
    event.preventDefault()
    //  how to filter data from the table component in combination with "filter component 1"
  }

  return (
    <>
      <form onSubmit={handleSubmit}>


        <ul>
          <p>Genotype</p>
          {genotype.map((name, index) => (
            <div className="form-check mb-3">
              <input
                className="form-check-input"
                type="checkbox"
                value={name.toLowerCase()}
                id={index + name}
                onChange={handleChange}
              />
              <label className="form-check-label" htmlFor={index + name}>
                {name}
              </label>
            </div>
          ))}
        </ul>

        <ul>
          <p>Treatment</p>
          {treatment.map((name, index) => (
            <div className="form-check mb-3">
              <input
                className="form-check-input"
                type="checkbox"
                value={name.toLowerCase()}
                id={index + name}
                onChange={handleChange}
              />
              <label className="form-check-label" htmlFor={index + name}>
                {name}
              </label>
            </div>
          ))}
        </ul>
        <button>Filter</button>
      </form>
    </>
  )
}

export default SidebarOptions

It would be great if someone could help me figure out an efficient way to filter and display data present on the 'table component' by using the filters which reside in different unrelated components.

Thanks in advance.

I could think of 3 ways you can approach this.

  1. Hoist the data from SampleList to a higher component where SidebarOptions and TissueOptions also exist. Which would look like this.
const [sample, setSample] = useState([])

// Handle loading of data 
useEffect(()=>{},[])

// Filter function
const handleFilter = (*expected params*) => {
  // code to handle filter changes

  setSample(filteredList)
}

return (
  <SampleTableWithFilter>
    <SidebarOptions onSubmit={handleFilter}/>
    <SampleList listData={sample} />
    <TissueOptions onSubmit={handleFilter}/>
  </SampleTableWithFilter>
)
  1. You could look into implementing react-redux or Redux-saga if you think the data will be used in many more other components. Will entail a bit more learning curve and tutorials to watch but it should help.

  2. You could also check Context API ( link ) from react to handle these.

Won't be adding samples of the last two since these are something you should look into as to how you would implement it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM