S
S
sinevik2018-03-13 16:04:10
React
sinevik, 2018-03-13 16:04:10

How to solve problem in React.js with checkbox?

z29826va.beget.tech
Please note, if you select a brand, select several models after the brand, and then select another brand - then it saves the selected checked in the checkbox. But why? How to solve this problem?
77fa0904d58f49f434a48fa2b184b0f1.png
Here are the 2
main components

import React from "react";
import Model from "./model";
import Sortcost from "./sortcost";
import Marka from "./marka";
import Body from "./body";
import Auto from "./auto";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import RouterDom from "react-router-dom";



class Main extends React.Component {
  constructor(props){
    super(props);
      this.state = {
          WeatherObj:null,
          mark:[],
          model:[],
          body:[],
          page:1,
          valueinputfrom:"",
          valueinputbefore:"",
          content:{
            display:"flex",
            flexDirection:"row"
          },
          stylecontainer:{
            display:"flex",
            flexDirection:"column"
          }
      }
    }
  
  changemark(e){
    let unit = e.target.value;
    let arr = this.state.mark;
    let arrtwo = this.state.model;
    if(e.target.value === "all"){
      arr.length = 0;
      arrtwo.length = 0;
      this.setState({mark: arr});
      this.setState({model: arrtwo});
      this.setState({page: 1});
    }else{
      arr.length=0;
   		arr.push(unit);
   		arrtwo.length = 0;
   		this.setState({model: arrtwo});
   		this.setState({mark: arr});	
   		this.setState({page: 1});
    }
    
  
  }

  changemodel(e){
    let unit = e.target.value;
    let arr = this.state.model;
   	if(e.currentTarget.checked === true){
   		arr.push(unit);
   		this.setState({model: arr});
   		this.setState({page: 1});
   	}else{
   		arr.splice(arr.indexOf(unit), 1);
   		this.setState({model: arr});
   		this.setState({page: 1});
   	}
  
  }
  changebody(e){
    let unit = e.target.value;
    let arr = this.state.body;
   	if(e.currentTarget.checked === true){
   		arr.push(unit);
   		this.setState({body: arr});
   		this.setState({page: 1});
   	}else{
   		arr.splice(arr.indexOf(unit), 1);
   		this.setState({body: arr});
   		this.setState({page: 1});
   	}
  
  }

  valueinputfrom(e) {
    let text = e.target.value;
    this.setState({valueinputfrom: text});
    this.setState({page: 1});
  }

  valueinputbefore(e) {
    let text = e.target.value;
    this.setState({valueinputbefore: text});
    this.setState({page: 1});
  }
  page(e) {
    let text = e.currentTarget.id;
    this.setState({page: text});
  }




  
  render() {

      	return(
    <div style={this.state.content}>
      	<div style={this.state.stylecontainer}>
      		<div>
      			<Marka changemark={this.changemark.bind(this)}/>
      		</div>
      		<div>
      			<Model mark={this.state.mark} changemodel={this.changemodel.bind(this)} />
      		</div>
      		<div>
      			<Body changebody={this.changebody.bind(this)}/>
      		</div>
      		<div>
      			<Sortcost meaningfrom={this.state.valueinputfrom} meaningbefore={this.state.valueinputbefore} from={this.valueinputfrom.bind(this)} before={this.valueinputbefore.bind(this)}  />
      		</div>
      	</div>
      	<div>
      		<div>
      			<Auto pagedata={this.state.page} page={this.page.bind(this)} mark={this.state.mark} model={this.state.model} body={this.state.body} from={this.state.valueinputfrom}  before={this.state.valueinputbefore} />
      		</div>
      	</div>
    </div>
      	
      	)
   	
  

  }

}
export default Main;

Model
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import RouterDom from "react-router-dom";


class Model extends React.Component {
  constructor(props){
    super(props);
      this.state = {
          mark:props.mark,
          stylelabel:{
            font: "15px Arial",
          },
          header:{
            font: "15px Arial",
            marginTop:"40px",
            marginBottom:0,

          },
          signature:{
            marginBottom: 0
          },

          stylecontainerinput:{
            display:"flex",
            flexDirection:"column",
            width:"100px",
            background:"#848482",
            borderRadius: "6px"
          }
        }
    }
  

  render() {
    let result = null;
    let header = null;
    if(this.state.mark.length > 0){
      header = <p style={this.state.header}>Модель</p>
      result = this.state.mark.map( (item, index)  => {
        if (item == "bmw") return (
            <div style={this.state.stylecontainerinput} key={index}>
              <label style={this.state.signature}>{item}</label>
              <div>
              <input id="X1" value="X1" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="X1">X1</label>
      						</div>
      						<div>
      						<input id="X5" value="X5" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="X5">X5</label>
      						</div>

      						<div>
      						<input id="X6" value="X6" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="X6">X6</label>
      						</div>
      						
      						
            </div>

          )
        if (item == "audi") return (
            <div style={this.state.stylecontainerinput} key={index}>
              <label style={this.state.signature}>{item}</label>
              <div>
              <input id="A3" value="A3" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="A3">A3</label>
      						</div>
      						<div>
      						<input id="A4" value="A4" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="A4">A4</label>
      						</div>

      						<div>
      						<input id="A7" value="A7" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="A7">A7</label>
      						</div>
      						
            </div>

          )
        if (item == "ford") return (
            <div style={this.state.stylecontainerinput} key={index}>
              <label style={this.state.signature}>{item}</label>
              <div>
              <input id="Mondeo" value="Mondeo" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="Mondeo">Mondeo</label>
      						</div>
      						<div>
      						<input id="Focus" value="Focus" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="Focus">Focus</label>
      						</div>
      						<div>
      						<input id="Kuga" value="Kuga" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="A7">Kuga</label>
      						</div>	
            </div>

          )
        if (item == "mazda") return (
            <div style={this.state.stylecontainerinput} key={index}>
              <label style={this.state.signature}>{item}</label>
              <div>
              <input id="323" value="323" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="323">323</label>
      						</div>

      						<div>
      						<input id="626" value="626" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="626">626</label>
      						</div>

      						<div>
      						<input id="3" value="3" type="checkbox" onClick={this.props.changemodel}/>
      						<label style={this.state.stylelabel} htmlFor="3">3</label>
      						</div>
      						
      						
            </div>

          )

      });
    }
    return (
    <div>
      {header}
      {result}
    </div>
    )

  }

    
}

export default Model;

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Anton Spirin, 2018-03-13
@sinevik

The reason for the bug is that you render lists of models via map and pass an index to key , and the index in your case is always 0 . The very decision to show lists in this way is very bad.
How can you change it. First, use not an array for mark , but a string. Using an array for the mark value is unreasonable. Secondly, all car models with filters are stored in the view object:

const allCars = {
  bmw: [
    { name: 'x1',  ... },
     ...
  ],
  ...
}

Then:
render() {
  const { mark } = this.props;
  const models = allCars[mark]; 
  
  return (
    <div>
      {mark && (
        <div>
          <label>{mark}</label>
          {models.map(model => (
            <div key={model.name}>
              <label>{model.name}</label>
              <input
                name="model"
                value={model.name}
                type="checkbox"
                onClick={this.props.changemodel}
              />
            </div>
          ))}
        <div>
      )}
    </div>
  );
}

You cannot change the state the way you do it, since the call to setState is asynchronous. For example, the changeMark method code can be rewritten like this:
changeMark (e) {
  const { value } = e.target;

  this.setState({ 
    mark: value === 'all' ? [] : [...prevState.mark, value],
    model: [],
    page: 1,
  });
  }
}

To change the state based on the previous one, pass a state-returning function to setState , at the time of the call, the first argument ( prevState in the example) will receive the current state of the component.
For variables whose value is not redefined, it is more correct to use const rather than let .
The changeBody and changeModel handlers can be combined into one, and using xor from lodash can be reduced to this form:
handleCheckboxCheck(e) {
    const { name, value } = e.target;

    this.setState(prevState => ({
      [name]: _.xor(prevState[name], +value), 
    }));
}

Black magic with array.push and array.length = 0 to update the state, forget and never remember.
The render method is the worst place for a handler bind. Antipattern. This can only be done if you need to pass arguments.
Instead, the bind is better done in the constructor:
constructor(props) {
  super(props);
  this.changeModel = this.changeModel.bind(this);
}

Or by rewriting the handler from a class method to a class field: class
method:
changeModel (e) {
    // some actions
}

class field:
changeModel = e => {
  // some actions
};

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question