【问题标题】:Communicate two React children components with onClick functionality使用 onClick 功能通信两个 React 子组件
【发布时间】:2017-04-30 09:35:07
【问题描述】:

好的,我将尽力解释我的项目是如何设置的,以便您可以适当地帮助我找出如何处理此配置。

我有一个parent component,即smart component。通过这个组件,可以访问我商店中的所有数据。

class DashboardPage extends React.Component {
  componentDidMount() {
   this.props.getTips();
  } 

  render() {
    return (
      <div>
        <div className="row">
          <div className="col-sm-7">
            <ContentBox
              title="The Scoop"
              footerText="Submit a Story"
              showSlider
              content={<TipOfTheDay tips={this.props.tips} />}
            />
          </div>
        </div>
      </div>
    )
  }
}

DashboardPage.propTypes = {
  getTips: PropTypes.func
}

function mapStateToProps(state, ownProps) {
  tips: state.tips
}

function mapDispatchToProps(dispatch) {
  return {
    getTips: () => { dispatch(tipActions.loadTips());} ## This hits tipActions and runs the `action creator`: loadTips(). Which returns all tips from api. 
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(DashboardPage);

如您所见,我在smart component、&lt;ContentBox/&gt; 和&lt;TipOfTheDay/&gt; 中包含了两个dumb components。在dashboardPage 上大约有7 个&lt;ContentBox/&gt; 组件,每个组件都继承了页眉/页脚的特殊标题,并且还通过showSlider 布尔值告知是否显示页脚。这是&lt;ContentBox/&gt; 的样子:

import React, {PropTypes} from 'react';
import Footer from './ContentBoxFooter';

const ContentBox = ({title, footerText, showSlider, content}) => {
  return (
    <div style={styles.root} className="col-sm-12">
      <div style={styles.header} className="row">
        <h3 style={styles.header.title}>{title}</h3>
        <span style={styles.header.arrow} />
      </div>
      {content}
      <Footer footerText={footerText} showSlider={showSlider} />
    </div>
  );
};

ContentBox.propTypes = {
  title: PropTypes.string,
  footerText: PropTypes.string,
  showSlider: PropTypes.bool,
  content: PropTypes.object
};

export default ContentBox;

这是页脚:

import React, {PropTypes} from 'react';
import styles from './contentBoxStyles';
import Previous from './svg/Previous';
import Next from './svg/Next';
import Add from './svg/Add'; 
import consts from '../../styles/consts';

const ContentBoxFooter = ({footerText, showSlider}) => {
  if (footerText != undefined) {
    return (
      <div style={styles.footer} className="row">
        {
          showSlider ? 
            <div> 
              <Previous fillColor={consts.orange} height="20px" width="20px"/>
              <span style={styles.bar}>|</span>
              <Next fillColor={consts.orange} width="20px" height="20px"/>
            </div> : <div style={styles.emptyArrow} />
        }
        <div style={styles.footer.link}>
          <span style={styles.footer.link.text}>{footerText}</span>
          <Add fillColor={consts.orange} height="24px" width="24px" />
        </div>
      </div>
    );
  } else {
    return(null);
  }
};

ContentBoxFooter.propTypes = {
  footerText: PropTypes.string,
  showSlider: PropTypes.bool
};

export default ContentBoxFooter;

很少!所以这里是我需要添加onClick 功能的地方。此功能需要添加到作为 SVG 的 &lt;Previous/&gt; 和 &lt;Next/&gt; 组件中。我试图做的是为我拉入的提示创建一个滑块。显然会有&lt;Footer/&gt; 组件需要相同的功能,但控制提示以外的不同数据。因为我是 React 和 Redux 的新手,所以我不知道如何执行此操作,而不仅仅是执行此操作,而是以“Redux”方式执行此操作。

如何让这两个嵌套在其他dumb components 中的svg 组件是dumb components,以对页面上的特定数据执行onClick 功能?我希望这是有道理的。为了更清楚,这是我对&lt;TipOfTheDay/&gt; 组件所做的事情:

const tipOfTheDay = ({tips}) => {
  return (
    <div style={styles.tipBody} className="row">
      {
        tips.map(function(tip, key) {
          return (
            <div key={key} className="myTips">
              <h3 style={styles.tipBody.header}>{tip.title}</h3>
              <p style={styles.tipBody.content}>{tip.content}</p>
            </div>
          );
        })
      }
    </div>
  );
};

tipOfTheDay.propTypes = {
  tips: PropTypes.array.isRequired
};

export default tipOfTheDay;

感谢您随时阅读/回复/协助此问题。我是一个相当新的开发人员,这对我来说也是新技术。

【问题讨论】:

    标签: javascript reactjs svg redux components


    【解决方案1】:

    我不确定你是如何实现下一个和上一个组件的,但是由于你使用了 React-Redux,你可以创建额外的容器来包装这些组件并将 Redux Action 传递给它们,例如:

    // PreviousComponent.jsx
    var Previous  React.createClass({
        propTypes: {
            goToPrevious: React.PropTypes.func,
        },
    
        render: function() {
            return (
                <div onClick={this.props.goToPrevious}>
                    ...
                </div>
            );
        }
    };
    
    export default Previous;
    
    //PreviousContainer.jsx
    import ReactRedux from 'react-redux';
    import Previous from './PreviousComponent';
    
    var mapStateToProps = (state, props) => {
        return {};
    };
    
    var mapDispatchToProps = (dispatch) => {
        return {
            goToPrevious: () => {
                dispatch(Actions.goToPrevious());
            },
        }
    };
    
    var PreviousContainer = ReactRedux.connect(
        mapStateToProps,
        mapDispatchToProps
    )(Previous);
    
    
    export default PreviousContainer;
    

    通过直接在您的组件周围添加容器包装器,您可以将用于转到上一个图像/幻灯片/任何内容的 redux 操作直接连接到您的 React 组件中。然后,当您想在 ContentBoxFooter 中使用该操作时,导入 PreviousContainer 并将其放置在您想要 Previous 组件的位置,例如:

    //ContentBoxFooter.jsx
    
    import PreviousContainer from './PreviousContainer'
    
    const ContentBoxFooter = ({footerText, showSlider}) => {
      if (footerText != undefined) {
        return (
          <div style={styles.footer} className="row">
            {
              showSlider ? 
                <div> 
                  /*
                   * Add the PreviousContainer here where before you were only using your regular Previous component.
                   */
                  <PreviousContainer fillColor={consts.orange} height="20px" width="20px"/>
                  <span style={styles.bar}>|</span>
                  <Next fillColor={consts.orange} width="20px" height="20px"/>
                </div> : <div style={styles.emptyArrow} />
            }
            <div style={styles.footer.link}>
              <span style={styles.footer.link.text}>{footerText}</span>
              <Add fillColor={consts.orange} height="24px" width="24px" />
            </div>
          </div>
        );
      } else {
        return(null);
      }
    };
    
    ContentBoxFooter.propTypes = {
      footerText: PropTypes.string,
      showSlider: PropTypes.bool
    };
    

    通过将 Next 和 Previous 组件包装在将操作传递给它们的容器中,您可以将 Redux 操作直接连接到您的组件中,而无需从应用程序的根组件传递它们。此外,这样做可以让您隔离调用某些操作的位置。您的上一个按钮可能是唯一想要调用上一个操作的组件,因此通过将其放置在组件周围的 Container 包装器中,您可以确保上一个操作仅在需要的地方使用。

    编辑:

    如果您必须处理多个操作,最好在更高级别定义它们。在这种情况下,由于 ContentBox 是常见的断点,我将为每种类型的内容框定义单独的 Previous 操作,并将它们传递给每个 ContentBox 实例:

    var DashboardApp =  React.createClass({
        propTypes: {
            TipsPrevious: React.PropTypes.function,
            NewsPrevious: React.PropTypes.function,
        },
    
        render: function() {
            <div>
                <ContentBox
                    previousAction={this.props.TipsPrevious}
                    contentType='Tips'
                />
                <ContentBox
                    previousAction={this.props.NewsPrevious}
                    contentType='News'
                />
                ...
           </div>
        },
    });
    

    通过子组件向下传递操作,直到到达上一个组件,然后将操作附加到上一个组件上的“onClick”处理程序。

    这背后的想法是您希望将参数的范围限制为尽可能少的代码。例如,如果您添加了一个在页面上显示您的用户信息的配置文件组件,您可能希望在该组件周围添加一个容器并传入与用户相关的信息/操作,而不将信息传递给应用程序的其余部分。通过这样做,可以更轻松地将信息集中在需要的地方。如果您必须修复错误,它还可以帮助您确定代码中发生了某些更改/操作的位置。

    在上面的示例中,如果 Dashboard 组件是您的根组件,您只需通过包装它的容器将 Redux Actions 传递到。但是,如果您的仪表板组件本身是一个嵌套组件,请通过自定义容器将操作传递给它,以便这些操作不会传播到不需要查看它的代码:

    <AppRoot>
        <PageHeader/>
        <DashboardContainer />
        <PageSidebar />
        <PageFooter />
    </AppRoot>
    

    【讨论】:

    • 感谢您的评论!我想我理解你的方法,但确实有一个问题。我将此页脚与多个 &lt;ContentBox/&gt; 组件一起使用。所以想象一下,3 个页脚都将具有此slider 功能。如果这些生成的组件中的每一个都需要分别为不同的数据运行,那么这个解决方案会起作用吗?示例:一个滑块影响Tips 组件,另一个影响...比如说...News 组件。
    • 根据您的评论更新了我的答案。
    猜你喜欢
    • 2020-10-16
    • 2021-10-10
    • 2021-04-14
    • 2021-07-30
    • 2021-10-04
    • 2020-03-23
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多