A bit of context for this table – I want to create a table where user can select an option in the dropdown on the table header and compare. So this table has two columns and each column represents the data that’s been selected.
What I want to achieve is when one is selected say business
in column one, how can I disable business
/ prevent it from being selected in column 2? As it doesn’t make sense to compare two of the same ones.
Also is there a better way to handle the onChange for the two select dropdowns? At the moment I have two methods and they are quite similar. I’ve tried to have only one onChange method but was not able to prevent both from changing when one is selected.
Here’s what I’ve done so far my table:
import React, { useEffect, useState } from "react"; import "./styles.css"; const Table = () => { const [plan, setPlan] = useState("business"); const [planToCompare, setPlanToCompare] = useState("pro"); const handleChange = (e) => { e.preventDefault(); setPlan(e.target.value); }; const handleChange2 = (e) => { e.preventDefault(); setPlanToCompare(e.target.value); }; const data = [ { business: ["Lorem", "Ipsum", "Dolor sit amet"], pro: ["Lorem 1", "Ipsum 2", "Dolor sit amet 3"], free: ["Lorem 4", "Ipsum 5", "Dolor sit amet 6"] } ]; const renderData = (plan1, plan2) => { const arr = data[0][plan1]; const arr2 = data[0][plan2]; return arr.map((item, index) => ( <tr key={`plan_${index + 1}`}> <td>{item}</td> <td>{arr2[index]}</td> </tr> )); }; return ( <div className="container"> <table> <thead> <tr> <th> <select datachosen={plan} onChange={(e) => handleChange(e)}> <option value={"business"}>Business</option> <option value={"pro"}>Pro</option> <option value={"free"}>Free</option> </select> </th> <th> <select id={"select2"} datachosen={planToCompare} onChange={(e) => handleChange2(e)} > <option value={"pro"}>Pro</option> <option value={"free"}>Free</option> <option value={"business"}>Business</option> </select> </th> </tr> </thead> <tbody>{renderData(plan, planToCompare)}</tbody> </table> </div> ); }; export default Table;
Here’s a working codesandbox for a full view
Advertisement
Answer
You need to keep the dropdown data in a variable, but as you initiating it in const data = ..
it will recreates every time when the components get rendered, so you need to keep it in a useState or use useMemo
useState: this is good if you want to change the data, for ex: add another option
const [data, setData] = useState([ { business: ["Lorem", "Ipsum", "Dolor sit amet"], pro: ["Lorem 1", "Ipsum 2", "Dolor sit amet 3"], free: ["Lorem 4", "Ipsum 5", "Dolor sit amet 6"] } ]);
useMemo: this is good if you are not willing to change the options.
const data = useMemo(() => { return [ { business: ["Lorem", "Ipsum", "Dolor sit amet"], pro: ["Lorem 1", "Ipsum 2", "Dolor sit amet 3"], free: ["Lorem 4", "Ipsum 5", "Dolor sit amet 6"] } ]; }, []);
and then I need two variables to hold the options for each dropdowns
// used useMemo because i want to update my planDropDownOptions only if data or planToCompare values gets changed const planDropDownOptions = useMemo(() => { return Object.keys(data[0]).filter((option) => option !== planToCompare); }, [data, planToCompare]); // used useMemo because i want to update my planToCompareDropDownOptions only if data or plan values gets changed const planToCompareDropDownOptions = useMemo(() => { return Object.keys(data[0]).filter((option) => option !== plan); }, [data, plan]);
now when we rendering the options it should be like
<select datachosen={plan} onChange={(e) => handleChange(e)}> {planDropDownOptions.map((option) => { return ( <option key={option} value={option}> {option} </option> ); })} </select>
here is the demo