簡體   English   中英

在ReactJS中,組件狀態是綁定到該組件的實例還是它綁定到該組件的所有實例?

[英]In ReactJS is component state tied to an instance of the component or is it tied to all instances of the component?

我正在嘗試在頁面上顯示組件的多個實例。 每個實例都應出現在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>

我正在使用語義UI的Tab組件在頁面上呈現此組件的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>
        }
    ]

在render方法中,我有:

                <Tab 
                    menu={{ secondary: true, pointing: true }} 
                    panes={panes} 
                />

在任何一個選項卡中觸發onClick處理程序都會更改組件所有實例中的狀態。 這正常嗎? 我認為組件的一個實例中的組件狀態是該實例所獨有的。

在進一步的調查中,我發現使用語義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);

經過深入研究並最終在Semantic UI的GitHub存儲庫上發布了一個問題 ,我了解到我需要在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>
        }
    ]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM