React-当同一组件有多个实例时,如何更改单个组件的状态? [英] React - How change state of single component when there are multiple instance of same component?

查看:309
本文介绍了React-当同一组件有多个实例时,如何更改单个组件的状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有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>
    );
  }
};

解决方案

您似乎无法决定是否要使用顶级组件或SingleTopicBox的状态,但是无论如何您都将其置于顶级组件中

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

如果可以让多个SingleTopicBox组件同时具有单击状态,则应将状态和onClick句柄移至SingleTopicBox.您无需记住组件是否被单击及其背景颜色.例如,您可以:

getInitialState: function() {
    return {
        bgDisplayColor: 'blue'
    };
},

onClick() {
    this.setState({bgDisplayColor: 'red'});
};

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

如果您一次只希望单击一个组件,以使先前单击的组件在单击另一个组件时又回到未单击状态,则您可能希望状态和处理程序位于顶级组件中,因为您已经在代码中添加了它.在该状态下,您唯一需要记住的是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>
    );
}

I have 4 boxes with component name SingleTopicBox. I would like to change color of box when user clicks on particular box. SingleTopicBox component has props topicID as a unique identifier for each box. Currently when user clicks on any of the box it's changing state of all the boxes bgDisplayColor: 'red' however, I would like to only change the color of boxes that is clicked.

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>
    );
  }
};

解决方案

You can't seem to decide whether you want the state for the top-level component or the SingleTopicBox, but you put it in the top-level component anyway.

You should make a choice: Should the SingleTopicBox component know it's been clicked or should MultiTopicsModuleIndex remember which SingleTopicBox has been clicked?

If you are ok with multiple SingleTopicBox component having the clicked state at the same time, you should move the state and the onClick hander to SingleTopicBox. You don't need to remember both if the component has been clicked and its background color. For example, you can:

getInitialState: function() {
    return {
        bgDisplayColor: 'blue'
    };
},

onClick() {
    this.setState({bgDisplayColor: 'red'});
};

then use this.state.bgDisplayColor in the render method

If you want only one component to be clicked at any single time, so that previously clicked component goes back to unclicked when another one is clicked, you may want to have the state and the handler live in the top-level component, as you already have it in your code. The only thing you need to remember in the state is topicID, then you pass it to the TopicsList component as property like this:

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

and in TopicsList you render something like this:

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>
    );
}

这篇关于React-当同一组件有多个实例时,如何更改单个组件的状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆