简体   繁体   中英

How to dynamically create an array of buttons in React using MonogoDB?

Im trying to convert my static product configurator into a dynamic one using the MERN stack, and I am really close to being done with the test version finally! I have everything working, but I am having trouble making it even more dynamic. In my configurator here for example, I have the ability to change colors through a list of hard coded buttons that trigger an event. This gets tedious with the amount of products that I will be trying to deploy to our website, and some products are only available in one, two, or three materials. I have successfully uploaded an array to MongoDB and is structured like so: 在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

So my main question is, how would I go about generating a list of buttons that are nested inside of an accordion like in my example above, while each "section" of the accordion would have the correlating name of that material selection.

Here is my hardcoded snipit of the HTML as well as some of the functions I have currently:

 import {useEffect, useState} from "react"; import {useSelector, useDispatch} from "react-redux"; // Actions import {getProductDetails} from "../redux/actions/productActions"; const ProductScreen = ({match}) => { const dispatch = useDispatch(); const productDetails = useSelector((state) => state.getProductDetails); const {loading, error, product} = productDetails; useEffect(() => { if (product && match.params.id !== product._id) { dispatch(getProductDetails(match.params.id)); } setCurrentSrc(product.src) }, [dispatch, match, product]); const changeColor = (event) => { const modelViewer = document.querySelector("model-viewer"); modelViewer.variantName = event.target.value; }; const [currentSrc, setCurrentSrc] = useState(product.src); return (*/HTML/*) }
 <div className="accordion"> <div> <input type="radio" name="accordion" id="Lacquer" className="accordion__input" /> <label htmlFor="Lacquer" className="materialLabel">Lacquer</label> <div className="items"> <button onClick={changeColor} className='item' value='Ballet Pink'>Ballet Pink</button> <button onClick={changeColor} className='item' value="Bellini Peach">Bellini Peach</button> <button onClick={changeColor} className='item' value="Boeing Navy">Boeing Navy</button> <button onClick={changeColor} className='item' value="Cessna Grey">Cessna Grey</button> <button onClick={changeColor} className='item' value="Charter Coral">Charter Coral</button> <button onClick={changeColor} className='item' value="Cirrus White">Cirrus White</button> <button onClick={changeColor} className='item' value="Citation Blue">Citation Blue</button> <button onClick={changeColor} className='item' value="Dash Pink">Dash Pink</button> <button onClick={changeColor} className='item' value="Falcon Grey">Falcon Grey</button> <button onClick={changeColor} className='item' value="Gulfstream Blue">Gulfstream Blue</button> <button onClick={changeColor} className='item' value="Havilland Sage">Havilland Sage</button> <button onClick={changeColor} className='item' value="Illuminating Yellow">Illuminating Yellow</button> <button onClick={changeColor} className='item' value="Lear Green">Lear Green</button> <button onClick={changeColor} className='item' value="Merlin Lavender">Merlin Lavender</button> <button onClick={changeColor} className='item' value="Midnight Green">Midnight Green</button> <button onClick={changeColor} className='item' value="Polar Ice">Polar Ice</button> <button onClick={changeColor} className='item' value="Smoky Blue">Smoky Blue</button> <button onClick={changeColor} className='item' value="Stratos Black">Stratos Black</button> <button onClick={changeColor} className='item' value="Vitamin C">Vitamin C</button> </div> </div> <div> <input type="radio" name="accordion" id="Wood" className="accordion__input" /> <label htmlFor="Wood" className="materialLabel">Wood</label> <div className="items"> <button onClick={changeColor} className='item' value="Golden Pecan Mappa Burl">Golden Pecan Mappa Burl</button> <button onClick={changeColor} className='item' value="Golden Pecan Olive Ash">Golden Pecan Olive Ash</button> <button onClick={changeColor} className='item' value="Natural Mappa Burl">Natural Mappa Burl</button> <button onClick={changeColor} className='item' value="Natural Olive Ash">Natural Olive Ash</button> <button onClick={changeColor} className='item' value="Provincial Mappa Burl">Provincial Mappa Burl</button> <button onClick={changeColor} className='item' value="Provincial Olive Ash">Provincial Olive Ash</button> </div> </div> </div>

Right now I can console.log(product.material) and see the product JSON, but I am unsure how to extract that information and plug it into a

Here is the redux/axios portion I use to getProductDetails:

 export const getProductDetails = (id) => async(dispatch) => { try { dispatch({type: actionTypes.GET_PRODUCT_DETAILS_REQUEST}); const {data} = await axios.get(`/api/products/${id}`); dispatch({ type: actionTypes.GET_PRODUCT_DETAILS_SUCCESS, payload: data, }); } catch (error) { dispatch({type: actionTypes.GET_PRODUCT_DETAILS_FAIL, payload: error.response && error.response.data.message ? error.response.data.message : error.message, }); } };

Any help would be greatly appreciated!

You should create a custom component for simplicity representing your input radio and loop

  1. The list of materials object
  2. The list of values inside it

In ProductScreen :

{
  product && product.materials.map((material) => (
    <CustomRadioButton material={material} changeColor={changeColor} />
  ));
}

Create a new CustomRadioButton component

export const CustomRadioButton = ({ material, changeColor }) => {
  const materialName = Object.keys(material)[0];
  if (!materialName) return <></>;
  return (
    <div>
      <input
        type='radio'
        name='accordion'
        id={materialName}
        className='accordion__input'
      />
      <label htmlFor={materialName} className='materialLabel'>
        {materialName}
      </label>
      <div className='items'>
        {material[materialName].map((item) => (
          <button onClick={changeColor} className='item' value={item}>
            {item}
          </button>
        ))}
      </div>
    </div>
  );
};

Okay, with the help of @LuccaPizzini I was able to figure out how to make it work! Here is what I had to do instead:

In Product Screen :

 { product && (product.materials ||).map((material, index) => ( <CustomRadioButton key={index} material={material} changeColor={changeColor} /> )) }

Create a new CustomRadioButton component:

 export const CustomRadioButton = ({ material, changeColor }) => { const materialName = Object.keys(material); if (!materialName) return <></>; return ( <div> <input type='radio' name='accordion' id={materialName} className='accordion__input' /> <label htmlFor={materialName} className='materialLabel'> {materialName} </label> <div className='items'> {material[materialName].map((item) => ( <button key={item} onClick={changeColor} className='item' value={item}> {item} </button> ))} </div> </div> ); };

Essentially, very small changes in both components from what he had provided.

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