简体   繁体   中英

How can I display dynamic state in react

I create a state dynamically, but I need use this state in my render.

See my issue:

handleChange = (name, checked) => {
  this.setState({
    [name]: checked,
  })
}

So, in my render how can I display my [name] state? (I don't know his name, since it's dynamic)

render(){

  console.log(this.state....?)

  return(
    <p>Hello</p>
  )
}

My function handleChange is called when I checked my checbkox. So, if I have 5, 10, 20 checkboxes how can I display my [name] state?

----> UPDATE - FULL CODE <----
I'm using a hover propriety to display my checkbox:

CSS using material ui:

  hideCheckbox: {
    display: 'none',
  },
  showCheckbox: {
    display: 'initial',
  },

My main class:

export class Item extends Component {

state = { 
  isHovering: true,
  checkboxChecked: false,
}

handleGetCardSelected = (id, checked) => { 
 //Here I set isHovering to display my checkbox
 //checkboxChecked is a control variable to always display the checkbox if it's checked

  if(checked){
    this.setState({
      isHovering: !this.state.isHovering,
      checkboxChecked: true,
    })

  } else {
    this.setState({
      checkboxChecked: false,
    })
  }
}

handleMouseHover = () => {
  if(!this.state.checkboxChecked){
    this.setState(this.toggleHoverState);
  }
}

toggleHoverState = (state) => {
  return {
    isHovering: !state.isHovering,
  };
}
return(
 <div 
   onMouseEnter={this.handleMouseHover} 
   onMouseLeave={this.handleMouseHover}
  >
   <div className={`
     ${this.state.isHovering && classes.hideCheckbox }
     ${this.state.checkboxChecked && classes.showCheckbox}
    `}>
      <CheckBoxCard handleGetCardSelected={this.handleGetCardSelected}/>
    </div>
  </div>

 <div 
   onMouseEnter={this.handleMouseHover} 
   onMouseLeave={this.handleMouseHover}
  >
   <div className={`
     ${this.state.isHovering && classes.hideCheckbox }
     ${this.state.checkboxChecked && classes.showCheckbox}
    `}>
      <CheckBoxCard handleGetCardSelected={this.handleGetCardSelected}/>
    </div>
  </div>

 <div 
   onMouseEnter={this.handleMouseHover} 
   onMouseLeave={this.handleMouseHover}
  >
   <div className={`
     ${this.state.isHovering && classes.hideCheckbox }
     ${this.state.checkboxChecked && classes.showCheckbox}
    `}>
      <CheckBoxCard handleGetCardSelected={this.handleGetCardSelected}/>
    </div>
  </div>
 )
 }

My CheckboxCard:

import React from 'react';
import { makeStyles, withStyles } from '@material-ui/core/styles';
import { Checkbox } from '@material-ui/core';
const GreenCheckbox = withStyles({
  root: {
    color: '#43a04754',
    '&$checked': {
      color: '#43a047',
    },
    '&:hover': {
      color: '#43a047',
      backgroundColor: 'initial',
    },
  },
  checked: {},
})(props => <Checkbox color="default" {...props} />);

export default function CheckBoxCard(props){
  const [state, setState] = React.useState({
    idItem: false,
  });

  const handleCheckbox = name => event => {
    setState({ ...state, [name]: event.target.checked });

    let id = name
    let checked = event.target.checked
    props.handleGetCardSelected(id, checked)
  };

  return(
    <GreenCheckbox
      checked={state.idItem}
      onChange={handleCheckbox('idItem')}
      value="idItem"
      inputProps={{
        'aria-label': 'primary checkbox',
      }}
    />
  );
}

By default, my checkbox is hidden because my state isHovering is true, so the css variable hideCheckbox ('display: none') is set.

If I hover the element, is called handleMouseHover and the checkbox is displayed!

If I checked my checkbox, is set checkboxChecked for true and now I'm always displaying my checkbox! But, if I've two or more elements, all checkbox is displayed, because checkboxChecked is an unique element!

So, my checkboxChecked must be dynamic and per item! In this way, if is checked , only this checkbox will be displayed. The others no!

For first element:
${this.state.checkboxCheckedITEM1 && classes.showCheckbox}

For second element:
${this.state.checkboxCheckedITEM2 && classes.showCheckbox}

For second element:
${this.state.checkboxCheckedITEM3 && classes.showCheckbox}

I update my code in sandbox: https://codesandbox.io/embed/material-demo-16t91?fontsize=14

How can I do that?

So, if I have 5, 10, 20 checkboxes how can I display my [name] state?

I think the smart way to do this is to nest components. Have an abstract parent component, that only renders the child component once the name is available. By using this pattern your problem can be solved.

Check out this helpful article

您可以过滤对象以仅获取已检查的名称。

Object.keys(this.state).filter(name => this.state[name]);

If you have a finite list of checkbox component

render() {
  return (
    <div>
      <Checkbox
        handleChange={() => this.handleChange('abc', !this.state[abc])}
        className={this.state['abc'] ? 'checked-class' : '' }
      />
    </div>
  )
}

In another situation whereby you render a list of dynamic checkbox.

componentDidMount() {
  //Calling API to return dynamic list of checkboxes, and dump them into a state
  this.setState({ listOfCheckboxes });
}

Then in your render method, you will be using .map function

render() {
  return (
    <div>
    {
      this.state.listOfCheckboxes.map(x => (
        <Checkbox
          handleChange={() => this.handleChange(x.name, !this.state[x.name]) }
          className={this.state[x.name] ? 'checked-class' : '' }
        />))
    }
    </div>
  )
}

通过这样做 :

this.state[name]

You can look at Object.keys() , but if in future you would need to handle more than one state, iteration does not seem to solve the problem.

You could also give it a prefix [name_${name}]: checked , but would not recommend that at all.

If it is not a problem, use an object and you will have full controll over it.

this.setState({
  something: {
    name,
    checked  
  },
})

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