如何在reactjs中将具有切换功能的状态组件转换为无状态组件?

时间:2020-07-26 18:41:06

标签: javascript reactjs

我正在尝试将以下组件转换为功能组件,以便可以使用react context API?

我要转换的组件的JSX代码

class pizzaModal extends Component {
  state = {
    selected: "small",
    showModal: true,
    selectedOrder: null
  }
  toggleHandler = (size)=> ()=>{
    this.setState({
            toggle: size
        });
  }
  addToOrders = (p)=>{
    this.setState(prevState=>({
      selectedOrder: p
    }))
  }
  
  render (){
    let attachedClasses = [styles.ImageContainer]
    if(this.state.toggle==='small'){
      attachedClasses = [styles.ImageContainer, styles.Small]
    }
    if(this.state.toggle==="medium"){
      attachedClasses = [styles.ImageContainer, styles.Medium]
    }
    if(this.state.toggle==="large"){
      attachedClasses=[styles.ImageContainer, styles.Large]
    }
    return (
      <Aux>
        <div className={styles.Pizzamodal}>
          <div className={styles.ModalContainer}>
            <div className={attachedClasses.join(' ')}>
              <img  src={this.props.image} alt="pizzapicture"/>
            </div>
            <div className={styles.DetailsContainer}>
              <div>
                <div className={styles.TextDetails}>
                  <h1>{this.props.name}</h1>
                  <p>{this.props.ingredients}</p>
                </div>
                <div>
                <div className={styles.Form}>
                <form className={styles.switchButton}>
                  <input type="radio" name="pizza" id="small" value="small" onChange={this.toggleHandler("small")}
                            checked={this.state.toggle==="small"}/>
                  <label for="small">Small</label>
                  <input type="radio" name="pizza" id="medium" value="medium" onChange={this.toggleHandler("medium")}
                            checked={this.state.toggle==="medium"}/>
                  <label for="medium">Medium</label>
                  <input type="radio" name="pizza" id="large" value="large" onChange={this.toggleHandler("large")}
                            checked={this.state.toggle==="large"}/>
                  <label for="large">Large</label>
                </form>
                </div>
                <div className={styles.orderButton}>
                  <button onClick={this.props.addToOrders}>Add to basket for ₦{this.props.price}</button>
                </div>
              </div>
              </div>
            </div>  
            <div className={styles.Navbar} onClick={this.props.clicked}>
            <div></div>
            <div></div>
          </div>
          </div>
         
      </div>
      </Aux>
    )
  }
}
export default pizzaModal;

这就是我所做的

const PizzaModal= (props) => {
  const [Selected, setSelected] = useState('small')
  
  const toggleHandler = (size)=>{
    setSelected({
            toggle: Selected
        });
  }
  /*const [orders, setOrders] = useContext([CartContext]);
  const addToOrders=()=>{
    const pizza = {name: this.props.name, ingredients: this.props.ingredients, image: this.props.image, price: this.props.price}
      setOrders([...orders, pizza])
  
  }*/
  
    let attachedClasses = [styles.ImageContainer]
    if(setSelected(Selected==='small')){
      attachedClasses = [styles.ImageContainer, styles.Small]
    }
    if(setSelected(Selected==="medium")){
      attachedClasses = [styles.ImageContainer, styles.Medium]
    }
    if(setSelected(Selected==="large")){
      attachedClasses=[styles.ImageContainer, styles.Large]
    }
    return (
      <Aux>
        <div className={styles.Pizzamodal}>
          <div className={styles.ModalContainer}>
            <div className={attachedClasses.join(' ')}>
              <img  src={props.image} alt="pizzapicture"/>
            </div>
            <div className={styles.DetailsContainer}>
              <div>
                <div className={styles.TextDetails}>
                  <h1>{props.name}</h1>
                  <p>{props.ingredients}</p>
                </div>
                <div>
                <div className={styles.Form}>
                <form className={styles.switchButton}>
                  <input type="radio" name="pizza" id="small" value="small" onChange={toggleHandler("small")}
                            checked={setSelected(Selected==='small')}/>
                  <label for="small">Small</label>
                  <input type="radio" name="pizza" id="medium" value="medium" onChange={toggleHandler("medium")}
                            checked={setSelected(Selected==='medium')}/>
                  <label for="medium">Medium</label>
                  <input type="radio" name="pizza" id="large" value="large" onChange={toggleHandler("large")}
                            checked={setSelected(Selected==='large')}/>
                  <label for="large">Large</label>
                </form>
                </div>
                <div className={styles.orderButton}>
                  <button >Add to basket for ₦{props.price}</button>
                </div>
              </div>
              </div>
            </div>  
            <div className={styles.Navbar} onClick={props.clicked}>
            <div></div>
            <div></div>
          </div>
          </div>
         
      </div>
      </Aux>
    )
  
}
export default PizzaModal;

在我的IDE或网页上没有错误消息,但是当我单击切换模式的按钮时,我得到了一个空白的白色屏幕,没有错误消息。

2 个答案:

答案 0 :(得分:1)

useState挂钩返回状态变量的当前值和用于更改状态变量的函数。就您而言

const [selected, setSelected] = useState('small')

您将在以前使用selected的任何地方使用this.state.selected,并在以前曾经使用setSelected()的任何地方使用this.setState({ selected })。因此,代码中的第一个问题是读取状态值时滥用setter函数。

要将函数传递给组件时,必须确保传递函数而不是调用函数。例如

onChange={toggleHandler("large")}

立即获取返回值toggleHandler("large"),并尝试在值更改时调用它。您对toggleHandler的定义不会返回任何内容,因此,当您更改单选按钮时,实际上只是在尝试将undefined作为函数来调用,这当然是行不通的。

此外,输入的onChange处理程序还会传递综合事件。您应该使用它来提取按下哪个单选按钮。

尝试这样的事情:

const PizzaModal = (props) => {
    const [selected, setSelected] = useState('small')
    
    const toggleHandler = (event) => {
      setSelected(event.target.value);
    }
  
    let attachedClasses = [styles.ImageContainer]
    if (selected === 'small')) {
      attachedClasses = [styles.ImageContainer, styles.Small]
    }
    if (selected === "medium")) {
      attachedClasses = [styles.ImageContainer, styles.Medium]
    }
    if (selected === "large")) {
      attachedClasses=[styles.ImageContainer, styles.Large]
    }
    return (
      <Aux>
        <div className={styles.Pizzamodal}>
          <div className={styles.ModalContainer}>
            <div className={attachedClasses.join(' ')}>
              <img  src={props.image} alt="pizzapicture"/>
            </div>
            <div className={styles.DetailsContainer}>
              <div>
                <div className={styles.TextDetails}>
                  <h1>{props.name}</h1>
                  <p>{props.ingredients}</p>
                </div>
                <div>
                <div className={styles.Form}>
                <form className={styles.switchButton}>
                  <input type="radio" name="pizza" id="small" value="small" onChange={toggleHandler} checked={selected === 'small'}/>
                  <label for="small">Small</label>
                  <input type="radio" name="pizza" id="medium" value="medium" onChange={toggleHandler} checked={selected === 'medium'}/>
                  <label for="medium">Medium</label>
                  <input type="radio" name="pizza" id="large" value="large" onChange={toggleHandler} checked={selected === 'large'}/>
                  <label for="large">Large</label>
                </form>
                </div>
                <div className={styles.orderButton}>
                  <button >Add to basket for ₦{props.price}</button>
                </div>
              </div>
              </div>
            </div>  
            <div className={styles.Navbar} onClick={props.clicked}>
            <div></div>
            <div></div>
          </div>
          </div>
         
      </div>
      </Aux>
    )
  
}
export default PizzaModal;

供以后参考,浏览器的Javascript控制台(通常在开发人员工具部分)中也会出现错误。您可以在那里检查错误。我的猜测是,试图将undefined作为函数进行调用以及由于setSelected调用而导致的渲染循环的某种组合是造成您的问题的原因。

答案 1 :(得分:1)

我在您的代码中发现的几个错误,看看这是否会改变

  1. 您不需要单独的toggleHandler函数来更改Selected的值,而setSelected正是该功能。
  2. 您给setSelected一个对象
setSelected({toggle: Selected});

相反,您应该为其赋予“已选择”的值

setSelected(Selected);
  1. 在所有if语句中
if(setSelected(Selected==='small'))

错了,您只需要检查

if(Selected==='small')

4。最后进入OnChange

onChange={toggleHandler("small")}

您可以只调用setSelected

onChange={() => setSelected("small")}