reactjs-两个组件之间的通信

时间:2019-06-05 12:15:37

标签: javascript reactjs

我想从一个组件到另一个组件调用一个函数。谷歌搜索后,我尝试了一些不同的事情,但是由于我是Reactjs的新手,所以我似乎无法解决问题。我以为可以导入状态,然后从其他组件中更改状态(请参见下文),但是我认为自己在树错了树皮?

我想从locationform.js调用header.js中的showMenu()

header.js

import React, { Component, PropTypes } from 'react';
import ReactF1 from 'react-f1';

// Styles.
import styles from './Header.css';

// Elements.
import Menu from './elements/Menu';

// Menu states.
import { states, SHOWBUTTON, IDLE, HIDE, OUT } from './elements/Menu/states';

import transitions from './elements/Menu/transitions';

function changeOffset() {
  document.querySelector('svg path').style.strokeDashoffset = 0;
  setTimeout("document.querySelector('svg path').style.strokeDashoffset = 171", 2000);
}

export default class Header extends Component {
  static get propTypes() {
    return {
      children: PropTypes.element,
    };
  }

  constructor(props, context) {
    super(props, context);

    this.state = {
      menuState: OUT,
      hamburgerState: OUT,
    };
  }

  componentDidMount() {
    if (this.props.router.location.pathname === '/') {
      setTimeout(() => this.setState({ hamburgerState: SHOWBUTTON }), 6000);
    } else {
      this.setState({ hamburgerState: SHOWBUTTON });
    }
    // setTimeout(changeOffset, 8000);
  }

  completeF1Handler() {}

  showMenu() {
    this.setState({ menuState: IDLE });
  }

  hideMenu() {
    this.setState({ menuState: HIDE });
  }

  reset() {
    this.setState({ menuState: OUT });
  }

  render() {
    const { stageWidth, stageHeight } = this.props;

    return (
      <ReactF1
        className={styles.Header}
        go={this.state.hamburgerState}
        states={states(stageWidth, stageHeight)}
        transitions={transitions()}
        onComplete={() => this.completeF1Handler()}
      >
        <svg className={styles.hamburger} data-f1="hamburger" width="50" height="50">
          <path
              className={styles.triangle}
              d="M0 0 L50 0 L0 50 Z"
              onClick={this.showMenu.bind(this)}
              fill={this.props.menuColor}
          />
        </svg>
        <Menu
          go={this.state.menuState}
          close={this.hideMenu.bind(this)}
          reset={this.reset.bind(this)}
        />
      </ReactF1>
    );
  }
}

locationform.js

import React, { Component, PropTypes } from 'react';
import { isDesktop } from '../../utils/device';
import LocateSelect from '../LocateSelect';

import styles from './LocationForm.css';
import buttonStyles from '../Button/Button.css';

// Menu states.
import { states, SHOWBUTTON, IDLE, HIDE, OUT } from '../Header/elements/Menu/states';

export default class LocationForm extends Component {
  static get propTypes() {
    return {
      zipCode: PropTypes.string,
      searchRadius: PropTypes.string,
      businessType: PropTypes.string,
      handleChange: PropTypes.func,
      handleGeolocate: PropTypes.func,
      handleSubmit: PropTypes.func,
    };
  }

  constructor(props, context) {
    super(props, context);
  }



  showMenu() {
    console.log("show menu");
      this.setState({ menuState: IDLE });
  }

  renderSelect() {
    const { searchRadius, businessType, handleChange } = this.props;

    return (
      <div className={styles.selectContainer}>
        <LocateSelect
          id="searchRadius"
          defaultValue=""
          value={searchRadius}
          handleChange={handleChange}
          options={[
            {
              value: '',
              text: 'SEARCH RADIUS',
            },
            {
              value: '1',
              text: '1 MI',
            },
            {
              value: '5',
              text: '5 MI',
            },
            {
              value: '10',
              text: '10 MI',
            },
            {
              value: '25',
              text: '25 MI',
            },
          ]}
        />
        <LocateSelect
          id="businessType"
          defaultValue=""
          value={businessType}
          handleChange={handleChange}
          options={[
            {
              value: '',
              text: 'BUSINESS TYPE',
            },
            {
              value: 'bar',
              text: 'Bar',
            },
            {
              value: 'restaurant',
              text: 'Restaurant',
            },
            {
              value: 'liquorstore',
              text: 'Liquor Store',
            },
          ]}
        />
      </div>
    );
  }

  render() {
    const {
      zipCode,
      handleChange,
      handleSubmit,
      handleGeolocate,
      handleFocus,
      handleBlur,
    } = this.props;

    return (
      <form className={styles.LocationForm} onSubmit={handleSubmit}>
        <input
          type="button"
          className={`${buttonStyles.Button} ${buttonStyles.dark} ${styles.geolocate}`}
          value="Use Current Location"
          onClick={handleGeolocate}
        />
        <p>OR</p>
        <input
          id="zipCode"
          type="text"
          placeholder="ZIP CODE"
          value={zipCode}
          maxLength="5"
          pattern="[0-9]*"
          onFocus={handleFocus}
          onBlur={handleBlur}
          onChange={event => handleChange(event.target.id, event.target.value)}
        />
        {this.renderSelect()}
        <input
          className={`${buttonStyles.Button} ${buttonStyles.dark}`}
          type="submit"
          value="search"
        />
          <div className={buttonStyles.Button} onClick={() => this.showMenu()}>
              No
          </div>
      </form>
    );
  }
}

3 个答案:

答案 0 :(得分:4)

在考虑父子通讯时,您必须为这两个文件编写父文件,并将函数和状态作为prop传递。

例如:

app.js

import Header from './header.js'
import LocationForm from './location-form.js'

export default class App extends Component {
  state = {menuState : 'out'}
  showMenu() {
    this.setState({ menuState:'idle' });
  }
  render(){
    return(
      <div>
        <Header showMenu={this.showMenu} menuState={this.state.menuState}/>
        <LocationForm showMenu={this.showMenu} menuState={this.state.menuState}/>
      </div>
    )
  }  
}

我认为这种思想观念将帮助您找到答案

答案 1 :(得分:0)

因此,在反应中,为了将数据从父元素传递到子元素,您需要将它们作为道具向下传递

因此,以您的Menu组件为例,您可以像这样将要使用的方法传递给该子组件:(我建议将它们转换为es6语法,这样就不必费心绑定了)。


//METHODS SECTION
const showMenu = () => {
    this.setState({ menuState: IDLE });
  }

  const hideMenu = () => {
    this.setState({ menuState: HIDE });
  }

  const reset = () => {
    this.setState({ menuState: OUT });
  }

//IN YOUR RENDER METHOD
<Menu
          go={this.state.menuState}
          close={this.hideMenu.bind(this)}
          reset={this.reset.bind(this)}
          showMenu={this.showMenu}
          hideMenu={this.hideMenu}
          reset={this.reset}
        />

然后在子组件中,将该方法称为this.props.showMenu或this.props.hideMenu或this.props.reset:

onClick(() => {this.props.showMenu()})

如果您希望该方法在事件上触发,则应像上面一样将其包装在一个匿名函数中。您还可以将其添加到子组件中的另一个方法中,该子方法在调用时将被调用,这样:

const doSomething = () => {
   count++
   this.props.showMenu()
}

onClick(() => {this.doSomething()})

在子组件中使用该方法时,它仍然绑定到父组件。这是将数据发送回父级的主要方法。例如,您可以让该方法简单地在父组件上设置一个值的setState,将该方法作为具有参数要求的道具传递给子对象,在子对象上传递参数,并在调用它时将其发送回父对象。 。 (让我知道这是否令人困惑)

您的应用中有很多不是非常“ Re​​act”的内容,因此,我绝对建议您仔细阅读其文档。从https://reactjs.org/docs/components-and-props.html开始,并在YouTube上观看一些有关React中状态管理的视频。

答案 2 :(得分:0)

父母之间的交流最好被认为具有两种操作方法:

  1. 父母可以传递孩子的道具
  2. 孩子可以调用从父母那里传递给他们的函数

这意味着组件之间的关系是通过定义的。他们的道具。这是一种通讯方式,可以更轻松地将组件构建为在特定上下文中可以连接的独立模块。

所以,如果您有类似的东西:

         Child A
       /
Parent
       \
         Child B

然后,您需要通过进行通信。 Parent。子代将调用其父代提供给他们的函数,父代会将新的prop传递给子代组件。

您还可以通过context来执行此操作,这样可以避免必须手动传递所有这些道具,但不会影响组件可用的通信流。

const ButtonComponent = (props) => {
  return (
    <div>
      Child
      <button onClick={props.handleClick}>
        Do the thing
      </button>
    </div>
  );
};

const CountDisplay = (props) => {
  return (
    <div>{props.count}</div>
  );
};

const Parent = (props) => {
  const parentLog = () => console.log('log from parent'); 
  const [
    currentCount,
    setCurrentCount,
  ] = React.useState(0);

  return (
    <div>
      Parent
      <ButtonComponent handleClick={() => setCurrentCount(currentCount + 1)} />
      <CountDisplay count={currentCount} />
    </div>
  );
};


ReactDOM.render(<Parent />, document.getElementById('app'))
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="app"></div>