【发布时间】:2019-07-23 08:15:35
【问题描述】:
我试图在一个页面上显示一个组件的多个实例。每个实例都应出现在 Tab.Pane(语义 UI 功能)中。然而,在我尝试实现这一点时,我遇到了一些奇怪的行为,如下面的详细说明。
我有一个组件; <MultistepFilterSection />
在这个组件中,状态是:
this.state = {
conjunction: "AND" // default
}
该状态由组件中的 onClick 处理函数修改;
handleConjunctionButtonClick = (conjunction, e) => {
this.setState({conjunction: conjunction})
}
这个 onClick 是通过点击两个按钮之一触发的:
<Button.Group vertical>
<Button
onClick={(e) => this.handleConjunctionButtonClick("AND")}
color={this.state.conjunction === "AND" ? "blue" : null}
>
And
</Button>
<Button
onClick={(e) => this.handleConjunctionButtonClick("OR")}
color={this.state.conjunction === "OR" ? "blue" : null}
>
Or
</Button>
</Button.Group>
我正在使用Semantic UI's Tab component 在页面上呈现此组件的 3 个实例;
const panes = [
{
menuItem: "Panel Data",
render: () =>
<Tab.Pane attached={false}>
<MultistepFilterSection getAudience={this.getAudience} />
</Tab.Pane>
},
{
menuItem: "Geolocation Data",
render: () =>
<Tab.Pane attached={false}>
<MultistepFilterSection getAudience={this.getAudience} />
</Tab.Pane>
},
{
menuItem: "Combined Audience Selection",
render: () =>
<Tab.Pane attached={false}>
<MultistepFilterSection getAudience={this.getAudience} />
</Tab.Pane>
}
]
在我的渲染方法中:
<Tab
menu={{ secondary: true, pointing: true }}
panes={panes}
/>
在任一选项卡中触发 onClick 处理程序会更改组件所有实例中的状态。这是正常的吗?我认为组件的一个实例中的组件状态是该实例独有的。
经过进一步调查,我发现当我使用 Semantic UI 的 Tab 组件实例化 <MultistepFilterSection /> 的多个实例时,会出现这种行为。当自己渲染实例时,会表现出预期的行为。
<MultistepFilterSection />组件的完整代码:
import React from "react";
import { Grid, Button, Container, Icon, Segment } from "semantic-ui-react";
import { connect } from "react-redux";
import uuid from "uuid";
import _ from "lodash";
import RuleGroup from "../rules/RuleGroup";
import { filterGroupCreated, filterGroupDeleted, filterDeleted } from "../../actions/FiltersAction"
export class MultistepFilterSection extends React.Component {
constructor(props) {
super(props);
this.state = {
conjunction: "AND" // default
}
// create one default group
this.props.filterGroupCreated({filterGroupId: uuid()})
this.handleAddRuleGroupButtonClick = this.handleAddRuleGroupButtonClick.bind(this);
this.renderRuleGroups = this.renderRuleGroups.bind(this);
this.handleConjunctionButtonClick.bind(this)
}
handleAddRuleGroupButtonClick() {
// console.log("called handleAddRuleGroupButtonClick()")
const filterGroupId = uuid()
let data = {}
data.filterGroupId = filterGroupId
this.props.filterGroupCreated(data)
}
handleConjunctionButtonClick = (conjunction, e) => {
this.setState({conjunction: conjunction})
}
renderRuleGroups() {
// console.log("called renderRuleGroups()")
return Object.values(this.props.filterGroups).map(function(ruleGroup) {
const key = ruleGroup.id;
// incomplete
let currentGenderSelected
return (
<React.Fragment key={key}>
<RuleGroup
id={key}
key={key}
deleteRuleGroup={this.deleteRuleGroup}
deleteFilter={this.deleteFilter}
currentGenderSelected={currentGenderSelected}
/>
</React.Fragment>
)
}.bind(this))
}
deleteRuleGroup = (id, e) => {
// console.log("delete rule group called")
this.props.filterGroupDeleted({filterGroupId: id})
}
deleteFilter = (filterGroupId, filterId, e) => {
// console.log("deleteFilter() called")
this.props.filterDeleted({
filterGroupId: filterGroupId,
filterId: filterId
})
}
render() {
const isFilterGroupQuery = true
return(
<Grid padded="vertically">
<Grid.Row stretched>
<Grid.Column verticalAlign={"middle"} width={2}>
{_.size(this.props.filterGroups) > 0 &&
<Segment basic>
<Button.Group vertical>
<Button
onClick={(e) => this.handleConjunctionButtonClick("AND")}
color={this.state.conjunction === "AND" ? "blue" : null}
>
And
</Button>
<Button
onClick={(e) => this.handleConjunctionButtonClick("OR")}
color={this.state.conjunction === "OR" ? "blue" : null}
>
Or
</Button>
</Button.Group>
</Segment>
}
</Grid.Column>
<Grid.Column width={14}>
{this.renderRuleGroups()}
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column width={2}></Grid.Column>
<Grid.Column width={3}>
<Button
color="grey"
basic
onClick={this.handleAddRuleGroupButtonClick}
>
<Icon name="plus" />Add Rule Group
</Button>
</Grid.Column>
<Grid.Column width={11}>
<Button
color="blue"
onClick={
(isFilterGroupQuery) => this.props.getAudience(
isFilterGroupQuery, this.state.conjunction
)
}
floated={"right"}
>
Run query
</Button>
</Grid.Column>
</Grid.Row>
</Grid>
)
}
}
function mapStateToProps(state) {
return {
filterGroups: state.filters
};
}
export default connect(
mapStateToProps,
{
filterGroupCreated,
filterGroupDeleted,
filterDeleted
}
)(MultistepFilterSection);
【问题讨论】:
-
肯定不正常,
state是组件实例,不应该共享。如果您需要进一步的帮助,您可能应该分享更多代码。 -
您需要在父组件外壳 MultistepFilterSection 中存储和管理状态。从那里您将按钮单击功能传递给每个组件。想法是,如果单击时调用任何 MultistepFilterSection 组件,则状态仅在父组件中更新。你应该看看 React 文档,因为它们非常好。以下链接准确描述了您想要做什么。 reactjs.org/docs/lifting-state-up.html
-
这是不正常的,只有被点击的组件才会更新状态,请分享您的代码,帮助我们提出修复建议。
-
您在哪里链接 onClick 处理程序 handleConjunctionButtonClick () ,请提供该代码。
-
分享MultiStepFilterSection组件完整代码
标签: javascript reactjs state