【问题标题】:In ReactJS is component state tied to an instance of the component or is it tied to all instances of the component?在 ReactJS 中,组件状态是与组件的实例相关联,还是与组件的所有实例相关联?
【发布时间】: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 组件实例化 &lt;MultistepFilterSection /&gt; 的多个实例时,会出现这种行为。当自己渲染实例时,会表现出预期的行为。

&lt;MultistepFilterSection /&gt;组件的完整代码:

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


【解决方案1】:

经过大量挖掘并最终在 Semantic UI 的 GitHub 存储库上使用 posting an issue,我了解到我需要在 Tab 组件上使用 renderActiveOnly={false} 属性。我还必须更改我的标记,以便窗格对象采用以下格式:

  const panes = [
        { 
            key: 1,
            menuItem: "Panel Data", 
            pane: <Tab.Pane><Simple key={1} /></Tab.Pane>
        },
        { 
            key: 2,
            menuItem: "Geolocation Data", 
            pane: <Tab.Pane><Simple key={2} /></Tab.Pane>
        }
    ]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-30
    • 1970-01-01
    • 2020-09-14
    • 2011-03-03
    • 2019-09-18
    • 2018-11-30
    • 2022-01-10
    相关资源
    最近更新 更多