So hello. I’ve been working on my own stuff as I believe it is the best way to learn things. So I got stuck, I am quite new to this react thing. I got this code, as you can see I have few checkboxes there, and what I want to achieve is to check the box to filter (hide) products from the array. I kinda got to the point where I don’t know what should I do next, I know I need to put something into constructor, but I can’t really figure out what. Can you please help me with that? Thanks!
class Shop extends React.Component { constructor(props) { super(props); this.state = { //I should put something here? } } render(){ let checkbox = (a) => { this.setState({cpu: a.target.checked}); } return (<div> <input type="checkbox" onChange={checkbox} name="cpu" id="cpu"></input> //I will do these later, so far I'd be happy to get cpu filter to work. <input type="checkbox" name="gpu" id="gpu"></input> <input type="checkbox" name="psu" id="psu"></input> <input type="checkbox" name="mb" id="mb"></input> <input type="checkbox" name="ram" id="ram"></input> <input type="checkbox" name="case" id="case"></input> {products.filter(product =>{ if (true) { return true; } }).map((shop) => <> <div id="prodinfo"> <p id="pname">{shop.name}</p> <p id="pprice">{shop.price}</p> <img src={shop.image} id="pimg" alt=""></img> </div> </>)} </div>); } } ReactDOM.render( <Shop/>, document.getElementById('maincontent') );
.group:after { content: ""; display: table; clear: both; } /* HEADER */ header { background-color: rgb(57,184,231); height: 9em; border-bottom: 2px solid blue; } .mainheader { margin: 0 auto; width: 70em; } .socialnetworks { display: flex; justify-content: flex-end; margin: -7px 0 0 0; width: 100%; background-color: rgb(0,170,203); height: 20px; } .socialnetworks i { padding-right: 20px; color: white; font-size: 20px; } .socialnetworks i:first-child:hover { color: rgb(66, 103, 178); cursor: pointer; } .socialnetworks i:last-child:hover { color: red; cursor: pointer; } .socicons { padding-right: 410px; } .socialnetworks i:last-child { padding: 0; } .logo { position: relative; top:0; left:0; max-width: 18%; font-size: 60px; color: white; } .logo span { font-weight: bolder; } .menu { text-align: center; } .menu span { margin-right: 15px; padding: 10px 10px 10px 10px; font-size: 25px; font-weight: bolder; } .menu span:hover { border-radius: 5px; background-color: rgb(33, 97, 194); cursor: pointer; } .menu a { text-decoration: none; color: whitesmoke; } .menu a:last-child { padding: 0; } .basket { position: absolute; top: 65px; right: 60px; } .basket span:hover { background-color: rgb(0, 140, 255); cursor: pointer; } .basket span { padding: 5px 5px 5px 5px; border: 1px solid grey; border-radius: 5px; background-color: rgb(0, 41, 128); color: whitesmoke; } /* MAIN_CONTENT */ #maincontent { padding-top: 10em; width: 1251px; margin: 0 auto; } #prodinfo { display: inline-block; width: 400px; height: 300px; border: 1px solid black; border-radius: 5px; margin: 0 15px 15px 0; } #pname { text-align: center; font-size: 30px; font-weight: bolder; } #pprice { position: relative; top: 165px; left: 60px; font-size: 20px; } #pimg { position: relative; bottom: 40px; left: 110px; height: 160px; width: 200px; } #pprice::after { content: "€"; } #prodfilters { text-align: center; }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://kit.fontawesome.com/a2faab1b70.js" crossorigin="anonymous"></script> <script src="database.js"></script> <script src="functions.js" type="text/babel"></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script src="https://unpkg.com/react@17/umd/react.production.min.js"></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script> <link rel="stylesheet" href="style.css"> <title>PCzone</title> </head> <body> <header> <div class="socialnetworks"> <div class="socicons"> <i class="fab fa-facebook-square"> Facebook</i> <i class="fab fa-youtube"> Youtube</i> </div> </div> <div class="mainheader"> <div class="logo"> <span>PC</span>zone </div> <div class="menu"> <span><a href="">Domov</a></span> <span><a href="">Zľavené produkty</a></span> <span><a href="">O nás</a></span> </div> <div class="basket"> <span><i class="fas fa-shopping-basket">Nákupný košík</i></span> </div> </div> </header> <div id="prodfilters"> <p>Filter produktov</p> </div> <div id="maincontent"> </body> </html>
Advertisement
Answer
class Shop extends React.Component { constructor(props) { super(props); this.state = { cpu: false, gpu: false, psu: false, mb: false, ram: false, case: false, } } render(){ let checkbox = (a) => { this.setState({ [a.target.name]: a.target.checked }); } return <div> {products.map(product=> { return <input type="checkbox" onChange={checkbox} name={product.type} id={product.type} /> })} {products.filter(product => { return this.state[product.type]; }).map((shop) => <div id="prodinfo"> <p id="pname">{shop.name}</p> <p id="pprice">{shop.price}</p> <img src={shop.image} id="pimg" alt="" /> </div>)} </div>;
Okay, so.. First of all, you need to set initial state to be able to trigger re-renders in you components (this what @alexsc _’s answer was about).
Second of all, if you’re trying to filter on an array of objects, you must have a field that you can use for that (note that I added a type variable that would contain the type of cpu or gpu, etc.. for each product). The React way to render multiple elements with similar values are usually done with mapping the related array (notice the mapping of products that returns an input element).
Following this logic, the third modification I made on your code was the filtering of products. This might not make any sense whatsoever, but when you click on an input element, it will trigger a re-render, due to the modification of a state member. This is why you need to have initial state and this is why I put the line, this.state[product.type]
in the filter. With this, React will detect a change in state and will attempt to re-render your component, which calls the filter method again with updated values.
To make it more clear, let’s say you filter by cpu
. You’ll click on the input which says cpu
. This will set the cpu
state variable to true
. React detects that the state has changed so it attempts a re-render. Then it’ll call the filter method on your products
array again and this.state[product.type]
will eventually be this.state['cpu']
which will evaluate to true
.
NOTE: If you’re unfamiliar with any of the used syntax, you should checkout the docs