Bootstrap v4 popover不会在React中的状态更改时更新

时间:2018-08-11 12:53:53

标签: reactjs twitter-bootstrap bootstrap-4 bootstrap-popover

我有一个“夜生活协调”应用程序(来自“免费代码营”课程),该应用程序允许用户在当天晚上按城市和RSVP搜索到酒吧。该应用程序保留了谁拥有RSVP以及谁将要去的列表。它是使用React和Bootstrap v4(以及后端的Node)构建的。

我在每个栏位置下都有文本,单击该文本可以使用户进行RSVP或取消RSVP。还有一个按钮,显示有多少人接受过RSVP,如果单击该按钮,将显示有RSVP接受者列表的Bootstrap弹出窗口。

如果用户有RSVP(或无RSVP),我希望列表更新。 (当前,按钮上的 number 会更新,但不会更新列表。)

以下两个图像显示了问题:

在初始加载时,所有功能均正常运行 enter image description here

当用户RSVPS或取消RSVP时,按钮上的数字会正确更新,但列表不会 enter image description here

这是我的代码。

列表是在render方法中第二个锚标记的data-content属性中生成的。

有人可以帮忙吗?

另一个提示是,在我的React开发人员工具Chrome扩展程序中,它显示了data-content属性在RSVP和unRSVP上已正确更新。也许Bootstrap会在初始渲染时将data-content属性的内容保存在其JS文件中,而不进行更新吗?

const React = require('react');

class Bar extends React.Component {  
  constructor(props) {
    super(props);
    this.state = {
      countMeIn: false, // coming from Mongo
      numberGoing: this.props.user_namesArr.length,
      user_id: this.props.twitter_id,
      user_name: this.props.user_name,
      yelp_id: this.props.yelp_id,
      user_namesArr: this.props.user_namesArr
    };
  }

  componentDidMount() { // need the same for DidMount and DidUpdate, in case user is signed in upon load (from previous session), or signs in after load
    if (this.state.user_namesArr.includes(this.props.user_name) && !this.state.countMeIn) {
      this.setState({
        countMeIn: true
      });
    }

  }

  componentDidUpdate(prevProps, prevState) { // Need both in case user logs in after initial page load
    console.log(this.state.user_namesArr);
    if (this.state.user_namesArr.includes(this.props.user_name) && !prevState.countMeIn) {
      this.setState({
        countMeIn: true
      });
    }
    $('[data-toggle="popover"]').popover();
  }


  rsvp() {
    let url = '/rsvp/?&yelp_id=' + this.props.yelp_id + '&user_id=' + this.props.twitter_id + '&user_name=' + this.props.user_name;
    fetch(url, { method: "POST" })
    .then((res) => res.json())
    .then((json) => {
      let newArr = this.state.user_namesArr;
      newArr.push(this.props.user_name);
      this.setState({
        numberGoing: this.state.numberGoing + 1,
        countMeIn: true,
        user_namesArr: newArr,
      });
    })
  }

  unrsvp() {
    let url = '/unrsvp/?&yelp_id=' + this.props.yelp_id + '&user_id=' + this.props.twitter_id + '&user_name=' + this.props.user_name;
    fetch(url, { method: "POST" })
    .then((res) => res.json())
    .then((json) => {
      let ind = this.state.user_namesArr.indexOf(this.props.user_name);
      let newArr = this.state.user_namesArr;
      newArr.splice(ind, 1);
      this.setState({
        numberGoing: this.state.numberGoing - 1,
        countMeIn: false,
        user_namesArr: newArr,
      });
    })
  }

  render() {
    return (
      <div className="col-lg-4 onecomponent">
        <a href={ this.props.bar_yelp_url } target="_blank">
        <div className="barname text-center">
          { this.props.name }
        </div>
        <div className="priceline">
          <img className="stars" src={ this.state.starsUrl } /> { this.props.review_count } reviews <span className="price">{ this.props.price }</span>
        </div>
        <div className="image">
          <img class="mainimg" src={ this.props.image_url } />
        </div>
        <div className="address text-center">
          { this.props.loc[0] }., { this.props.loc[1] }
        </div>
        </a>
        <hr/>
        <div className="text-center">
          <a tabindex="0" role="button" className="btn btn-success" data-toggle={ this.state.user_namesArr.length > 0 ? "popover" : "" } data-trigger="focus" title="Who's In?" data-content={ this.state.user_namesArr }>
            { this.state.numberGoing } going
          </a>
          {
            this.props.loggedIn ?
            this.state.countMeIn ?
            <span className="going" onClick={ () => this.unrsvp() }>You're going!</span> : // if logged in and already RSVP'd
            <span className="rsvpdetails" onClick={ () => this.rsvp() }>Count me in!</span> : // if logged in but not yet RSVP'd
            <span> Please log in </span> // if not logged in
          }
        </div>
      </div>
    )
  }

}

module.exports = Bar;

2 个答案:

答案 0 :(得分:0)

也许使用ref会有所帮助...但是为什么不使用reactstrap,更重要的是为什么不使用react-popper ...?众所周知(https://github.com/FezVrasta/popper.js/#react-vuejs-angular-angularjs-emberjs-etc-integration),许多库无法与React或任何其他(虚拟)DOM管理器配合使用。

您真的需要jQuery吗?

使用react门户,您可以删除所有这些依赖项。

答案 1 :(得分:0)

它与Reactstrap一起使用。我只是将reactstrap添加到我的package.json文件中,并使用了Reactstrap代码。

const React = require('react');
import { Button, Popover, PopoverHeader, PopoverBody } from 'reactstrap';

class Bar extends React.Component {  
  constructor(props) {
    super(props);
    this.state = {
      countMeIn: false, // coming from Mongo
      numberGoing: this.props.user_namesArr.length,
      user_id: this.props.twitter_id,
      user_name: this.props.user_name,
      yelp_id: this.props.yelp_id,
      user_namesArr: this.props.user_namesArr,
      popover: false
    };
    this.toggle = this.toggle.bind(this);
  }

  componentDidMount() { // need the same for DidMount and DidUpdate, in case user is signed in upon load (from previous session), or signs in after load
    if (this.state.user_namesArr.includes(this.props.user_name) && !this.state.countMeIn) {
      this.setState({
        countMeIn: true
      });
    }        
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.user_namesArr.includes(this.props.user_name) && !prevState.countMeIn) {
      this.setState({
        countMeIn: true
      });
    }
  }


  rsvp() {
    let url = '/rsvp/?&yelp_id=' + this.props.yelp_id + '&user_id=' + this.props.twitter_id + '&user_name=' + this.props.user_name;
    fetch(url, { method: "POST" })
    .then((res) => res.json())
    .then((json) => {
      let newArr = this.state.user_namesArr;
      newArr.push(this.props.user_name);
      this.setState({
        user_namesArr: newArr,
        numberGoing: this.state.numberGoing + 1,
        countMeIn: true
      });
    })
  }

  unrsvp() {
    let url = '/unrsvp/?&yelp_id=' + this.props.yelp_id + '&user_id=' + this.props.twitter_id + '&user_name=' + this.props.user_name;
    fetch(url, { method: "POST" })
    .then((res) => res.json())
    .then((json) => {
      let ind = this.state.user_namesArr.indexOf(this.props.user_name);
      let newArr = this.state.user_namesArr;
      newArr.splice(ind, 1);
      this.setState({
        user_namesArr: newArr,
        numberGoing: this.state.numberGoing - 1,
        countMeIn: false
      });
    })
  }

  toggle() {
    this.setState({
      popover: !this.state.popover
    });
  }

  render() {
    return (
      <div className="col-lg-4 onecomponent">
        <a href={ this.props.bar_yelp_url } target="_blank">
        <div className="barname text-center">
          { this.props.name }
        </div>
        <div className="priceline">
          <img className="stars" src={ this.state.starsUrl } /> { this.props.review_count } reviews <span className="price">{ this.props.price }</span>
        </div>
        <div className="image">
          <img class="mainimg" src={ this.props.image_url } />
        </div>
        <div className="address text-center">
          { this.props.loc[0] }., { this.props.loc[1] }
        </div>
        </a>
        <hr/>
        <div className="text-center">
          { /* For this to work, id must have leading letters, otherwise throws massive errors. See here: https://stackoverflow.com/questions/23898873/failed-to-execute-queryselectorall-on-document-how-to-fix */ }
          <Button id={ "abc" + this.props.yelp_id } className="btn btn-success" onClick={ this.toggle }>{ this.state.numberGoing } going</Button>
          <Popover placement="right" isOpen={ this.state.popover } target={ "abc" + this.props.yelp_id } toggle={ this.toggle }>
            <PopoverHeader>Who's In?</PopoverHeader>
            <PopoverBody>{ this.state.user_namesArr }</PopoverBody>
          </Popover>
          {
            this.props.loggedIn ?
            this.state.countMeIn ?
            <span className="going" onClick={ () => this.unrsvp() }>You're going!</span> : // if logged in and already RSVP'd
            <span className="rsvpdetails" onClick={ () => this.rsvp() }>Count me in!</span> : // if logged in but not yet RSVP'd
            <span> Please log in </span> // if not logged in
          }
        </div>
      </div>
    )
  }

}

module.exports = Bar;