使用复选框React

时间:2018-04-22 01:24:58

标签: javascript reactjs

我很擅长做出反应并且真的陷入困境。我正在开发一种订购应用程序。人们可以订购产品,并可以选择他们想要的所有成分。我想用每个成分的复选框做这个。 Unfort。我只是不知道如何解决这个问题。另外,我想知道我是否必须在我的组件中使用状态或仅使用变量。

所以我正在通过成分数组进行映射,对于每种成分我都会显示一个复选框来打开/关闭一种成分。所以我的主要问题是,我如何使用这些复选框调整我的对象,如果我需要在我的组件中有一个状态以跟上复选框的最新状态,我将如何将产品设置为我的状态?因为它来自道具。

我尝试过各种各样的事情,例如来自文档:

  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

但话又说回来,我怎样才能将产品添加到我的州?此外,这将是不同的,因为成分在对象中,文档中的示例只是值而不是特定对象。

我的组件

import React from 'react';
import { Link } from 'react-router-dom';

class Order extends React.Component {

    constructor(props) {
        super(props);
    }

    handleToggle(e) {

        //Handle the toggle, set the value of the ingredient to 0 or 1

    }

    getData(e, product) {

        e.preventDefault();

        console.log(product)

    }

    render() {

        const product = this.props.products.find((product) => {
            return product.id == this.props.match.params.id;
        });

        return (

            <form className="container mx-auto px-4 pt-6" onSubmit={(e) => this.getData(e, product) }>

                <Link to={`/${this.props.match.params.category}`} className="mb-4 relative block text-brand hover:text-brand-dark">&larr; Terug naar categorie</Link>

                <div className="flex flex-row items-center justify-between bg-white rounded px-8 py-8 shadow-sm mb-4">

                    <div className="">
                        <h2 className="text-brand uppercase">{product && product.name}</h2>
                        <div className="ingre">
                            <p>
                                {product && product.ingredients.map((item) => {
                                    return <span className="ing text-grey-dark text-sm" key={item.name}>{item.name}</span>
                                })}
                            </p>
                        </div>
                    </div>

                    <div className="">
                        <h3 className="text-brand text-4xl">&euro;{product && product.price}</h3>
                    </div>

                </div>

                <div className="flex flex-wrap mb-4 -mx-2">

                    {product && product.ingredients.map((item) => {
                        return (
                            <div className="w-1/2 mb-4 px-2" key={item.name}>
                                <div className="flex flex-row items-center justify-between bg-white rounded px-8 py-8 shadow-sm">
                                    <div>
                                        <h3 className="text-grey-dark font-normal text-sm">{item.name}</h3>
                                    </div>
                                    <div>
                                        <input type="checkbox" checked={item.value} name={item} onChange={(e) => this.handleToggle(e)}/>
                                    </div>
                                </div>
                            </div>
                        );
                    })}

                </div>

                <button type="submit" className="bg-brand hover:bg-brand-dark text-white font-bold py-4 px-4 rounded">
                    Order this product
            </button>

            </form>

        );

    }

}

export default Order;

产品示例

enter image description here

所以实际上我需要跟踪产品并将成分的值绑定到复选框。如果未选中,则该值必须为0(或为假)。

编辑:

父组件传递道具

// React deps
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";

// Custom components
import Navigation from './components/General/Navigation'

// Pages
import Index from './components/Index'
import Category from './components/Category'
import Order from './components/Order'

// Data
import products from './Data'

class App extends Component {

  constructor(props) {

    super(props);

    this.state = {
      products: []
    }

  }

  componentWillMount() {

    setTimeout(() => {
      this.setState({products});
    }, 100);

  }

  render() {
    return (
      <main className="App font-sans">
        <Router>
          <div>

            <Navigation logo="Jackies" />
            <Switch>
              <Route exact path="/" component={Index} />
              <Route exact path="/:category" render={(props) => <Category {...props} products={this.state.products} />}/>
              <Route exact path="/:category/:id" render={(props) => <Order {...props} products={this.state.products} />}/>
            </Switch>

          </div>
        </Router>

      </main>
    );
  }
}

export default App;

2 个答案:

答案 0 :(得分:1)

在父级中,您将在onIngredientToggle道具中传递处理函数:

<Route exact path="/:category/:id" render={(props) => <Order {...props} products={this.state.products} onIngredientToggle={this.handleIngredientToggle} />}/>

然后定义handleIngredientToggle函数:

function handleIngredientToggle(productId, ingredientIndex, newIngredientValue) {
    // basically this goes shallow cloning the objects and arrays up to
    // the point it changes the ingredient value property
    let products = [...this.state.products];
    let modifiedProductIndex = products.findIndex(p => p.id === productId);
    let product = {...products[modifiedProductIndex]};
    products[modifiedProductIndex] = product;
    product.ingredients = [...products[modifiedProductIndex].ingredients];
    product.ingredients[ingredientIndex] = {...product.ingredients[ingredientIndex], value: newIngredientValue};

    this.setState({products});
}

// If you prefer, the above function can be replaced with:
function handleIngredientToggle(productId, ingredientIndex, newIngredientValue) {
    // deep clone products
    let products = JSON.parse(JSON.stringify(this.state.products));
    // modify just what changed
    products.find(p => p.id === productId).ingredients[ingredientIndex].value = newIngredientValue;

    this.setState({products});
}

Order子项中,您将index参数添加到map(您有两个,只需添加到第二个):

{product && product.ingredients.map((item, index) => {

在复选框中将productindex传递给handleToggle函数作为参数:

<input type="checkbox" checked={item.value} name={item} onChange={(e) => this.handleToggle(e, product, index)}/> 

然后在函数实现中,您将从父级调用作为prop接收的函数:

handleToggle(e, product, index) {
    this.props.onIngredientToggle(product.id, index, e.target.checked);
}

答案 1 :(得分:0)

感谢@acdcjunior打开我疲惫的眼睛,我找到了解决方案

Checkbox html

<input type="checkbox" checked={item.value} name={item} onChange={(e) => this.handleToggle(e, item, product)}/>

子组件上的函数

handleToggle(e, item, product) {

    //Get value from checkbox and set it the opposite
    let value = e.target.checked ? 1 : 0;

    //Pass down the item (ingredient) and parent product and also the value
    this.props.toggleIngredient(item, product, value);

}

在父组件上更改状态的功能

  toggleIngredient(i, p, v) {

    // Get the product from the state
    var product = this.state.products.find((product) => {
      return product.id == p.id
    });

    // Filter down the state array to remove the product and get new products array
    let products = this.state.products.filter((product) => {
      return product != product;
    });

    // Get the ingredient object 
    var object = product.ingredients.find((product) => {
      return product == i;
    });

    // Set the value for the ingredient, either true or false (depends on checkbox state)
    object.value = v;

    // Push the edited product the array of products
    products.push(product);

    // Set the state with the new products array
    this.setState({
      products: products
    });

  }