在列表内动态渲染输入字段

时间:2019-07-23 12:25:58

标签: html reactjs

我有一组组件,其中包含输入字段和文本行。 enter image description here 如图中所给,用户应该能够添加类别和描述。添加它们后,它们将被呈现为组件列表。像这样 enter image description here 在一个类别内,将有如上图所示的标签,要添加它们,我必须添加一个输入组件。仅当用户单击每个类别行下方的“添加标签”按钮时,此输入组件才可用。当用户单击它时,它应启用输入(应在所选类别行内呈现输入组件),并且应该能够在其上键入标签名称并保存。我仅在单击添加标签按钮时才需要启用此输入字段。并且只能在所选类别行中启用。这是我尝试过的代码。

import React, { Component, Fragment } from "react";
import { Button, Header, Input } from "semantic-ui-react";
import "semantic-ui-css/semantic.min.css";
import ReactDOM from "react-dom";

class App extends Component {
  state = {
    category: "",
    description: "",
    categories: []
  };

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

  addCategory = () => {
    let { category, description } = this.state;
    this.setState(prevState => ({
      categories: [
        ...prevState.categories,
        {
          id: Math.random(),
          title: category,
          description: description,
          tags: []
        }
      ]
    }));
  };

  addTag = id => {
    let { tag, categories } = this.state;
    let category = categories.find(cat => cat.id === id);
    let index = categories.findIndex(cat => cat.id === id);
    category.tags = [...category.tags, { name: tag }];
    this.setState({
      categories: [
        ...categories.slice(0, index),
        category,
        ...categories.slice(++index)
      ]
    });
  };

  onKeyDown = e => {
    if (e.key === "Enter" && !e.shiftKey) {
      console.log(e.target.value);
    }
  };

  tags = tags => {
    if (tags && tags.length > 0) {
      return tags.map((tag, i) => {
        return <Header key={i}>{tag.name}</Header>;
      });
    }
  };

  enableTagIn = id => {};

  categories = () => {
    let { categories } = this.state;
    return categories.map(cat => {
      return (
        <Fragment key={cat.id}>
          <Header>
            <p>
              {cat.title}
              <br />
              {cat.description}
            </p>
          </Header>
          <Input
            name="tag"
            onKeyDown={e => {
              this.onKeyDown(e);
            }}
            onChange={this.onChange}
          />
          <Button
            onClick={e => {
              this.addTag(cat.id);
            }}
          >
            Add
          </Button>
          {this.tags(cat.tags)}
        </Fragment>
      );
    });
  };

  render() {
    return (
      <Fragment>
        {this.categories()}
        <div>
          <Input name="category" onChange={this.onChange} />
          <Input name="description" onChange={this.onChange} />
          <Button onClick={this.addCategory}>Save</Button>
        </div>
      </Fragment>
    );
  }
}

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

这是codesandbox网址。  关于如何实现这一目标的任何想法?。

1 个答案:

答案 0 :(得分:1)

我通过使用功能组件和React Hook更改了您的代码,并创建了类别组件,其状态如下:

   import React, { Fragment } from "react";
import { Button, Header, Input } from "semantic-ui-react";
import "semantic-ui-css/semantic.min.css";
import ReactDOM from "react-dom";

const App = () => {
  const [Category, setCategory] = React.useState({
    title: "",
    description: ""
  });
  const [Categories, setCategories] = React.useState([]);
  return (
    <div>
      {console.log(Categories)}
      <Input
        value={Category.title}
        onChange={e => setCategory({ ...Category, title: e.target.value })}
      />
      <Input
        value={Category.description}
        onChange={e =>
          setCategory({ ...Category, description: e.target.value })
        }
      />
      <Button onClick={() => setCategories([...Categories, Category])}>
        Save
      </Button>
      <div>
        {Categories.length > 0
          ? Categories.map(cat => <CategoryItem cat={cat} />)
          : null}
      </div>
    </div>
  );
};

const CategoryItem = ({ cat }) => {
  const [value, setvalue] = React.useState("");
  const [tag, addtag] = React.useState([]);
  const [clicked, setclicked] = React.useState(false);
  const add = () => {
    setclicked(false);
    addtag([...tag, value]);
  };
  return (
    <Fragment>
      <Header>
        <p>
          {cat.title}
          <br />
          {cat.description}
        </p>
      </Header>
      <Input
        name="tag"
        value={value}
        style={{ display: clicked ? "initial" : "none" }}
        onChange={e => setvalue(e.target.value)}
      />
      <Button onClick={() => (clicked ? add() : setclicked(true))}>Add</Button>
      <div>{tag.length > 0 ? tag.map(tagname => <p>{tagname}</p>) : null}</div>
    </Fragment>
  );
};

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

这里是sandbox