【问题标题】:React - How change state of single component when there are multiple instance of same component?React - 当有相同组件的多个实例时如何更改单个组件的状态?
【发布时间】:2016-05-29 02:24:01
【问题描述】:

我有 4 个组件名称为 SingleTopicBox 的盒子。当用户单击特定框时,我想更改框的颜色。 SingleTopicBox 组件有 props topicID 作为每个盒子的唯一标识符。目前,当用户单击任何框时,它会更改所有框 bgDisplayColor: 'red' 的状态,但是,我只想更改被单击框的颜色。

index.jsx

import {React, ReactDOM} from '../../../../build/react';

import SelectedTopicPage from './selected-topic-page.jsx';
import TopicsList from './topic-list.jsx';
import topicPageData from '../../../content/json/topic-page-data.js';

export default class MultiTopicsModuleIndex extends React.Component {

  constructor(props) {
    super(props);
    this.setTopicClicked = this.setTopicClicked.bind(this);
    this.onClick = this.onClick.bind(this);
    () => topicPageData;
    this.state = {
      isTopicClicked: false,
      bgDisplayColor: 'blue'
    };
  };

  onClick(topicID) {
    this.setState({isTopicClicked: true, topicsID: topicID, bgDisplayColor: 'red'});
  };

  setTopicClicked(boolean) {
    this.setState({isTopicClicked: boolean});
  };

  render() {
    return (
      <div className="row">
        {this.state.isTopicClicked
          ? <SelectedTopicPage topicsVisited={this.topicsVisited} setTopicClicked={this.setTopicClicked} topicsID={this.state.topicsID} key={this.state.topicsID} topicPageData={topicPageData}/>
        : <TopicsList bgDisplayColor={this.state.bgDisplayColor} topicsVisited={this.topicsVisited} onClick={this.onClick}/>}
      </div>
    );
  }
};

topic-list.jsx

import {React, ReactDOM} from '../../../../build/react';

import SingleTopicBox from './single-topic-box.jsx';
import SelectedTopicPage from './selected-topic-page.jsx';

export default class TopicsList extends React.Component {
  render() {
    return (
      <div className="row topic-list">
        <SingleTopicBox bgDisplayColor={this.props.bgDisplayColor} topicID="1" onClick={this.props.onClick} label="Topic"/>
        <SingleTopicBox bgDisplayColor={this.props.bgDisplayColor} topicID="2" onClick={this.props.onClick} label="Topic"/>
        <SingleTopicBox bgDisplayColor={this.props.bgDisplayColor} topicID="3" onClick={this.props.onClick} label="Topic"/>
        <SingleTopicBox bgDisplayColor={this.props.bgDisplayColor} topicID="4" onClick={this.props.onClick} label="Topic"/>
      </div>
    );
  }
};

Single-topic-box.jsx

import {React, ReactDOM} from '../../../../build/react';

export default class SingleTopicBox extends React.Component {
  render() {
    var divStyle = {
      backgroundColor: this.props.bgDisplayColor
    };
    return (
      <div>
        <div className="col-sm-2">
          <div style={divStyle} className="single-topic" data-topic-id={this.props.topicID} onClick={() => this.props.onClick(this.props.topicID)}>
            {this.props.label}
            {this.props.topicID}
          </div>
        </div>
      </div>
    );
  }
};

【问题讨论】:

    标签: javascript css reactjs ecmascript-6


    【解决方案1】:

    您似乎无法决定是想要顶级组件还是 SingleTopicBox 的状态,但无论如何您都将它放在顶级组件中。

    您应该做出选择:SingleTopicBox 组件是否应该知道它已被单击,或者 MultiTopicsModuleIndex 是否应该记住哪个 SingleTopicBox 已被单击?

    如果您可以同时使用多个具有单击状态的 SingleTopicBox 组件,则应将状态和 onClick 处理程序移动到 SingleTopicBox。如果组件已被单击,您不需要记住它的背景颜色。例如,您可以:

    getInitialState: function() {
        return {
            bgDisplayColor: 'blue'
        };
    },
    
    onClick() {
        this.setState({bgDisplayColor: 'red'});
    };
    

    然后在渲染方法中使用this.state.bgDisplayColor

    如果您希望在任何时候只单击一个组件,以便在单击另一个组件时先前单击的组件返回到未单击状态,您可能希望将状态和处理程序放在顶级组件中,因为您的代码中已经有了它。在 state 中唯一需要记住的是 topicID,然后将其作为属性传递给 TopicsList 组件,如下所示:

    <TopicsList clickedTopicID={this.state.topicID} onClick={this.onClick} />
    

    然后在 TopicsList 中呈现如下内容:

    render: function() {
        var topics = [
            {id: 1, label: 'Topic'},
            {id: 2, label: 'Topic'},
            {id: 3, label: 'Topic'},
            {id: 4, label: 'Topic'},
        ];
    
        var boxes = [];
    
        for (var i = 0, len = topics.length; i < len; i++)
            boxes.push(<SingleTopicBox 
                bgDisplayColor={(this.props.clickedTopicID == topics[i].id) ? 'red' : 'blue'}
                topicID={topics[i].id}
                onClick={this.props.onClick}
                label={topics[i].label}
            />);
    
        return (
          <div className="row topic-list">
            {boxes}
          </div>
        );
    }
    

    【讨论】:

    • 我尝试了你在 for 循环中建议的第二个选项,但是现在它没有呈现之前工作的 SelectedTopicPage 组件。
    • 你没有在问题描述中包含那个,所以我不知道到底出了什么问题。您是否检查过您是否在一个地方使用 this.state.topicsID 而在另一个地方使用 this.state.topicID?
    • 我将主题数组 id 值转换为字符串,从而解决了问题。但是,当组件重新安装时,我正在失去状态。如何保存状态?
    • 组件通常在页面首次打开时挂载,并在其 props 或 state 更改或您对其调用 forceUpdate() 时重新呈现。除非您刷新页面或以其他方式导航并返回它,否则它永远不应重新安装。如果你想在访问页面之间保留状态,它超出了 React 的范围,你应该查看本地存储或服务器端存储。
    猜你喜欢
    • 1970-01-01
    • 2021-08-09
    • 1970-01-01
    • 2019-06-14
    • 1970-01-01
    • 2020-07-14
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    相关资源
    最近更新 更多