*帮助* 使用钩子将 class 转换为功能组件
*Help* Convert class to functional component using hooks
我正在尝试将 EditableTabGroup
转换为功能组件 Tags
但是我似乎无法正确转换它,因为我正在尝试删除 this.
。
EditableTabGroup 工作正常,但是当我在 Taskform
中渲染 Tags
时它不起作用。
此外,如何清除状态标签,以便 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;
所以,为了让它工作,我改变了 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
"state"。这里有两个问题。第一个是你在 if 块内分配一个 let
,这意味着它不能从块外部访问,因此行 setState(state)
只是将状态设置为相同的状态( 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>
);
};
至于重置标签,您可以在Taskform.js
中定义state
状态,并将其作为道具传递给Tags
。这样你就可以在 Taskform.js
.
上重置 state
(setState([])
)
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;
当然,您还应该从 Tags.js
中删除 [state, setState] = useState([])
。
希望对您有所帮助!
我正在尝试将 EditableTabGroup
转换为功能组件 Tags
但是我似乎无法正确转换它,因为我正在尝试删除 this.
。
EditableTabGroup 工作正常,但是当我在 Taskform
中渲染 Tags
时它不起作用。
此外,如何清除状态标签,以便 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;
所以,为了让它工作,我改变了 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
"state"。这里有两个问题。第一个是你在 if 块内分配一个 let
,这意味着它不能从块外部访问,因此行 setState(state)
只是将状态设置为相同的状态( 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>
);
};
至于重置标签,您可以在Taskform.js
中定义state
状态,并将其作为道具传递给Tags
。这样你就可以在 Taskform.js
.
state
(setState([])
)
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;
当然,您还应该从 Tags.js
中删除 [state, setState] = useState([])
。
希望对您有所帮助!