根据num值渲染多个项目,仅渲染一个

时间:2019-07-13 09:54:37

标签: javascript reactjs

前提是我正在建立费用表格,并有一个按钮(尚未转到该组件),该按钮上添加了其他项目。我有一个函数可以在下面的代码中呈现多个组件,目前,在构建时,我有this.state.expenseData.expenseNum = 4,但只显示了一个。

我从控制台获得的输出是arr,将按预期输出[0、1、2、3],expenseItems仅包含一项。

renderExpenses() {
        const fillRange = (start, end) => {
            return Array(end - start + 1).fill().map((item, index) => start + index);
          };
        var arr = new Array(fillRange(0, this.state.expenseData.expenseNum - 1))
        console.log(arr)
        const expenseItems = arr.map((number) => <ExpenseContainer key={number}/>);
        console.log(expenseItems)
        return expenseItems

1 个答案:

答案 0 :(得分:1)

您可以像这样在给定范围内动态创建N个组件: https://codesandbox.io/s/dynamic-expense-form-jp8zm

App.js

import React from "react";
import ReactDOM from "react-dom";
import ExpenseContainer from "./ExpenseContainer";

import "./styles.css";

class App extends React.Component {
  state = {
    numberOfExpenses: null,
    showForm: false,
    allExpenses: []
  };

  createInitialExpense = () => {
    this.setState({
      showForm: true
    });
  };

  handleOnChange = event => {
    this.setState({
      [event.target.name]: event.target.value
    });
  };

  createForm = () => {
    const arrRange = Array.from(
      Array(parseInt(this.state.numberOfExpenses || 0)).keys()
    );

    return (
      <div>
        <h4>Expense List</h4>
        {arrRange.map((item, index) => {
          return (
            <ExpenseContainer
              key={index}
              index={index}
              updateExpenseList={this.updateExpenseList}
            />
          );
        })}
        <button onClick={this.addExpense}>Add</button>
      </div>
    );
  };

  updateExpenseList = (index, updatedExpense) => {
    const { allExpenses } = this.state;

    if (!allExpenses[index]) {
      const updatedExpenses = [...allExpenses];
      updatedExpenses[index] = updatedExpense;
      this.setState({
        allExpenses: [...updatedExpenses]
      });
    } else {
      const updatedExpenses = allExpenses.map((expense, expenseIndex) => {
        if (index == expenseIndex) {
          return {
            ...expense,
            ...updatedExpense
          };
        } else {
          return expense;
        }
      });

      this.setState({
        allExpenses: updatedExpenses
      });
    }
  };

  addExpense = () => {
    this.setState({
      numberOfExpenses: parseInt(this.state.numberOfExpenses || 0) + 1
    });
  };

  generateTotal = () => {
    const { allExpenses } = this.state;

    if (allExpenses && allExpenses.length) {
      const total = allExpenses.reduce((total, curr) => {
        return curr.expense ? total + curr.expense : total + 0;
      }, 0);
      return total;
    } else {
      return 0;
    }
  };

  render() {
    const { numberOfExpenses, showForm } = this.state;
    return (
      <div>
        <input
          placeholder="Number of expenses"
          type="number"
          name="numberOfExpenses"
          value={numberOfExpenses}
          onChange={this.handleOnChange}
        />
        <button onClick={this.createInitialExpense}>Create Expense Form</button>
        <p>Total: {this.generateTotal()}</p>

        {showForm ? <div>{this.createForm()}</div> : null}
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

ExpenseContainer.js

import React from "react";

class ExpenseContainer extends React.Component {
  state = {
    name: "",
    expense: ""
  };

  handleOnChange = e => {
    this.setState(
      {
        [e.target.name]: e.target.value
      },
      () => this.updateExpenseList()
    );
  };

  updateExpenseList = () => {
    const updatedExpense = {
      name: this.state.name,
      expense: parseInt(this.state.expense || 0)
    };

    this.props.updateExpenseList(this.props.index, updatedExpense);
  };

  render() {
    const { name, expense } = this.state;
    return (
      <div>
        <label>Name:</label>
        <input
          name="name"
          type="text"
          value={name}
          onChange={this.handleOnChange}
        />
        <label>Value:</label>
        <input
          name="expense"
          type="number"
          value={expense}
          onChange={this.handleOnChange}
        />
      </div>
    );
  }
}

export default ExpenseContainer;