使用onClick功能与两个React子组件通信

时间:2016-12-14 22:05:07

标签: javascript reactjs svg redux components

好吧,我会尽力解释我的项目是如何设置的,这样你就可以适当地帮助我找到如何处理这个配置。

我的parent componentsmart 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);

正如您所看到的,我在dumb componentssmart component和{}中包含了两个<ContentBox/><TipOfTheDay/>。在dashboardPage上有大约7个<ContentBox/>组件,每个组件都继承了页眉/页脚的特殊标题,并且还通过showSlider布尔值告知是否显示页脚。以下是<ContentBox/>的样子:

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功能。此功能需要添加到<Previous/>&amp;作为SVG的<Next/>组件。我试图做的是为我提取的提示创建一个滑块。显然,<Footer/>组件将需要相同的功能,但控制除提示之外的其他数据。因为我是React&amp;的新手Redux,我不知道如何执行此操作而不仅仅是执行此操作,而是以“Redux”方式执行此操作。

如何获取嵌套在svg的其他dumb components中的这两个dumb components组件,以便对页面上的特定数据执行onClick函数?我希望这是有道理的。为了更加清晰,以下是我使用<TipOfTheDay/>组件所做的事情:

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;

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

1 个答案:

答案 0 :(得分:1)

我不确定你是如何实现你的Next和Previous组件的,但是既然你已经使用了React-Redux,你可以创建额外的Containers来包装这些组件并将Redux Action传递给它们,例如: / p>

// 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操作直接连接到组件中,而无需从应用程序的根组件传递它们。此外,执行此操作可以隔离调用某些操作的位置。您的Previous按钮可能是唯一想要调用Previous操作的组件,因此通过将其放在组件周围的Container包装器中,您可以确保Previous操作仅用于需要它的位置。

编辑:

如果您必须处理多个操作,最好在更高级别定义它们。在这种情况下,由于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>
    },
});

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

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

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

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