*帮助*使用钩子将类转换为功能组件

时间:2019-12-01 12:34:03

标签: reactjs react-hooks react-props react-component react-ref

我正在尝试将EditableTabGroup转换为功能组件Tags,但是在尝试删除this.时似乎无法正确转换。

EditableTabGroup可以正常工作,但是当我在Tags中渲染Taskform时,它将无法工作。

此外,如何清除状态标签,以便onCreate(submit)标签为空数组?

class EditableTagGroup extends React.Component {
  state = {
    tags: [],
    inputVisible: false,
    inputValue: ""
  };

  handleClose = removedTag => {
    const tags = this.state.tags.filter(tag => tag !== removedTag);
    console.log(tags);
    this.setState({ tags });
  };

  showInput = () => {
    this.setState({ inputVisible: true }, () => this.input.focus());
  };

  handleInputChange = e => {
    this.setState({ inputValue: e.target.value });
  };

  handleInputConfirm = () => {
    const { inputValue } = this.state;
    let { tags } = this.state;
    if (inputValue && tags.indexOf(inputValue) === -1) {
      tags = [...tags, inputValue];
    }
    console.log(tags);
    this.setState({
      tags,
      inputVisible: false,
      inputValue: ""
    });
  };

  saveInputRef = input => (this.input = input);

  forMap = tag => {
    const tagElem = (
      <Tag
        closable
        onClose={e => {
          e.preventDefault();
          this.handleClose(tag);
        }}
      >
        {tag}
      </Tag>
    );
    return (
      <span key={tag} style={{ display: "inline-block" }}>
        {tagElem}
      </span>
    );
  };

  render() {
    const { tags, inputVisible, inputValue } = this.state;
    const tagChild = tags.map(this.forMap);
    const { getFieldDecorator } = this.props;

    return (
      <div>
        <div style={{ marginBottom: 16 }}>
          <TweenOneGroup
            enter={{
              scale: 0.8,
              opacity: 0,
              type: "from",
              duration: 100,
              onComplete: e => {
                e.target.style = "";
              }
            }}
            leave={{ opacity: 0, width: 0, scale: 0, duration: 200 }}
            appear={false}
          >
            {tagChild}
          </TweenOneGroup>
        </div>
        {inputVisible && (
          <Input
            ref={this.saveInputRef}
            onChange={this.handleInputChange}
            onPressEnter={this.handleInputConfirm}
            value={inputValue}
            onBlur={this.handleInputConfirm}
            type="text"
            size="small"
            style={{ width: 78 }}
          />
        )}
        {getFieldDecorator("tags", {
          initialValue: this.state.tags
        })(
          <Input
            ref={this.saveInputRef}
            type="text"
            size="small"
            style={{ display: "none" }}
          />
        )}
        {!inputVisible && (
          <Tag
            onClick={this.showInput}
            style={{ background: "#fff", borderStyle: "dashed" }}
          >
            <Icon type="plus" /> New Tag
          </Tag>
        )}
      </div>
    );
  }
}

export default EditableTagGroup;

Edit laughing-morning-rwktl

1 个答案:

答案 0 :(得分:2)

因此,为了使它起作用,我进行了两项更改:

1)您没有从文件中导出标签。在此示例中,我将其导出为命名导出,但是您可能应该将其导出为默认导出(export default Tags)。

2)第二个问题是代码的这一部分:

 const handleInputConfirm = () => {
    if (inputValue && state.indexOf(inputValue) === -1) {
      let state = [...state, inputValue];
    }
    setState(state);
    setInputVisible(false);
    setInputValue("");
  };

在if条件中,在其中检查当前标签和用户要添加的标签,您定义了let“状态”。这里有两个问题。第一个是您要在if块内分配一个let,这意味着不能从该块外部访问它,因此,行setState(state)只是将状态设置为相同的状态(状态是指状态变量state,而不是您在if块中定义的新state

第二个问题并不是真正的问题,您不应该分配名称与上限范围内的变量相同的新变量。您可能现在已经知道这是一个坏习惯。

详细了解let及其范围规则here

这是Tags的完整工作代码:

import React, { useState } from "react";
import { Tag, Input, Icon } from "antd";
import { TweenOneGroup } from "rc-tween-one";

export const Tags = props => {
  const [state, setState] = useState([]);
  const [inputVisible, setInputVisible] = useState(false);
  const [inputValue, setInputValue] = useState("");

  const handleClose = removedTag => {
    const tags = state.filter(tag => tag !== removedTag);
    setState(tags);
  };

  const showInput = () => {
    setInputVisible(true);
  };

  const handleInputChange = e => {
    setInputValue(e.target.value);
  };

  const handleInputConfirm = () => {
    if (inputValue && state.indexOf(inputValue) === -1) {
      var newState = [...state, inputValue];
      setState(newState);
    }
    setInputVisible(false);
    setInputValue("");
  };

  const saveInputRef = input => (input = input);

  const forMap = tag => {
    const tagElem = (
      <Tag
        closable
        onClose={e => {
          e.preventDefault();
          handleClose(tag);
        }}
      >
        {tag}
      </Tag>
    );
    return (
      <span key={tag} style={{ display: "inline-block" }}>
        {tagElem}
      </span>
    );
  };

  const tagChild = state.map(forMap);
  const { getFieldDecorator } = props;

  return (
    <div>
      <div style={{ marginBottom: 16 }}>
        <TweenOneGroup
          enter={{
            scale: 0.8,
            opacity: 0,
            type: "from",
            duration: 100,
            onComplete: e => {
              e.target.style = "";
            }
          }}
          leave={{ opacity: 0, width: 0, scale: 0, duration: 200 }}
          appear={false}
        >
          {tagChild}
        </TweenOneGroup>
      </div>
      {inputVisible && (
        <Input
          ref={saveInputRef}
          onChange={handleInputChange}
          onPressEnter={handleInputConfirm}
          value={inputValue}
          onBlur={handleInputConfirm}
          type="text"
          size="small"
          style={{ width: 78 }}
        />
      )}
      {getFieldDecorator("tags", {
        initialValue: state.tags
      })(
        <Input
          ref={saveInputRef}
          type="text"
          size="small"
          style={{ display: "none" }}
        />
      )}
      {!inputVisible && (
        <Tag
          onClick={showInput}
          style={{ background: "#fff", borderStyle: "dashed" }}
        >
          <Icon type="plus" /> New Tag
        </Tag>
      )}
    </div>
  );
};

关于重置标签,您可以在state内定义Taskform.js状态,并将其作为道具传递给Tags。这样,您可以在state上重置setState([])Taskform.js)。

Taskform.js:

const [tags, setTags] = useState([]);

const handleCreate = () => {
    form.validateFields((err, values) => {
      if (err) {
        return;
      }

      form.resetFields();
      onCreate(values);
      setTags([]);
    });
  };

...

<Tags
   getFieldDecorator={getFieldDecorator}
   state={tags}
   setState={setTags}
/>

Tags.js:

...
const { state, setState } = props;

当然,您还应该从[state, setState] = useState([])中删除Tags.js

希望有帮助!