使用React / Redux和生命周期事件处理存储更新

时间:2016-09-13 02:37:41

标签: reactjs redux react-redux rails-api

我在前端使用React和Redux,并使用Rails API来处理我的后端。目前,我正在尝试根据用户添加文章更新文章列表。 ArticleForm组件触发一个成功更新我的ArticleList的动作创建者。但是,目前生命周期方法componentWillUpdate不断触发向Rails发出axios请求,Rails不断查询我的数据库并发送回articleList。

注意:我尝试过使用shouldComponentUpdate无济于事,DOM没有更新:

// shouldComponentUpdate(newProps){
  //   return newProps.articleList !== this.props.articleList
  // }

我的问题是:如何在我的articleList更新时使用React的生命周期方法来避免这种情况发生,并且只发生 。我是否会使用生命周期方法走错路?我对React / Redux相当新,所以任何建议都有帮助!

我有以下容器:

    import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import ArticleForm from './ArticleForm'
import ArticleList from './ArticleList'
import removeArticle from '../actions/removeArticle'
import fetchArticles from '../actions/fetchArticles'
import updateArticleList from '../actions/updateArticleList'

class DumbArticleContainer extends Component {
  componentWillMount() {
    this.props.fetchArticles()
  }

  // shouldComponentUpdate(newProps){
  //   return newProps.articleList !== this.props.articleList
  // }

  componentWillUpdate(newProps){
    if (newProps.articleList.articleList.count !== this.props.articleList.articleList.count){
      this.props.updateArticleList()
    }
  }

  render() {
    return(
      <div>
        <ArticleForm />
        <ArticleList articleList={this.props.articleList} />
      </div>
    )
  }
}

const ArticleContainer = connect(mapStateToProps, mapDispatchToProps)(DumbArticleContainer)

function mapStateToProps(state) {
  return {articleList: state.articleList}
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({removeArticle, fetchArticles, updateArticleList}, dispatch);
}

export default ArticleContainer

这是ArticleForm

import React, { Component, PropTypes } from 'react'
import { reduxForm } from 'redux-form'
import addArticle from '../actions/addArticle.js'

class ArticleForm extends Component {

  constructor(props) {
    super(props)
    this.state = {disabled: true}
  }

  /* Most article elements are displayed conditionally based on local state */
  toggleState(){
    this.setState({
      disabled: !this.state.disabled
    })
  }

  handleFormSubmit(props) {
    event.preventDefault()
    const {resetForm} = this.props

    this.props.addArticle(props).then( ()=>{
      var router = require('react-router')
      router.browserHistory.push('/dashboard')
      resetForm()
    })
  }

  render() {
    const disabled = this.state.disabled ? 'disabled' : ''
    const hidden = this.state.disabled ? 'hidden' : ''

    const {fields: {title, url}, handleSubmit} = this.props;

    return (
      <div className="article-form">

        <form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
              <button className="article-form-btn"
                      hidden={!hidden}
                      onClick={this.toggleState.bind(this)}
                      >
                      + Add Article
              </ button>
              <input className="article-form-input"
                     hidden={hidden}
                     type="textarea"
                     placeholder="Title"
                     {...title}
                     />

              <input className="article-form-input"
                     hidden={hidden}
                     type="textarea"
                     placeholder="Paste Link"
                     {...url}
                     />

              { this.state.disabled
                ? ''
                : <input className="article-form-input"
                         type="submit"
                         value="Save"
                        />
              }
        </form>
      </div>
    );
  }
}

export default reduxForm({
    form: 'articleForm',
    fields: ['title', 'url']
  },
  null,
  { addArticle })(ArticleForm);

和ArticleList

import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import removeArticle from '../actions/removeArticle.js'
import fetchArticles from '../actions/fetchArticles'
import { ListGroup } from 'react-bootstrap'
import { ListGroupItem } from 'react-bootstrap'

class Article extends Component {


  render(){
    var articleList = this.props.articleList.articleList

    return(
      <div>
        <ListGroup>

          { articleList.slice(articleList.length - 10, articleList.length)
            .map( (article) => {
              return(
                <ListGroupItem href="#" header={article.attributes.title}>
                  {article.attributes.url}
                </ListGroupItem>
              )}
          )}

        </ListGroup>
        <div> View All Articles </div>
      </div>

    )
  }
}

const ArticleList = connect(mapStateToProps, mapDispatchToProps)(Article)

function mapStateToProps(state) {
  return {articleList: state.articleList}
}

function mapDispatchToProps(dispatch) {
  return  {removeArticle: bindActionCreators({removeArticle}, dispatch),
  fetchArticles: bindActionCreators({fetchArticles}, dispatch)
    }
}

export default ArticleList

动作创作者:

所以这是我的动作创建者从&#39; axios&#39;

导入axios
import axios from 'axios'

function updateArticleList(){

  const url = 'http://localhost:3000/api/v1/articles'
  return axios.get(url).then( (response)=> {
    return {
      type: 'UPDATE_ARTICLE_LIST',
      payload: response.data
    }
  })
}
export default updateArticleList

和reducer:

   export default function articleReducer(state = {articleList: []}, action) {
  switch(action.type){
    case 'FETCH_ARTICLES':
      return Object.assign({}, state, {articleList: action.payload.data});
    case 'UPDATE_ARTICLE_LIST':
      return Object.assign({}, state, {articleList: action.payload.data});
    default:
      return state
  }
}

商店,动作创作者和减速器都没有问题,它们都运作良好。我无法复制rails正在执行的数百个查询,但如果有人需要查看,我很乐意包含其他代码。

谢谢!

2 个答案:

答案 0 :(得分:1)

您的mapDispatchToProps使用了bindActionCreators错误。而不是

function mapDispatchToProps(dispatch) {
  return  {removeArticle: bindActionCreators({removeArticle}, dispatch),
  fetchArticles: bindActionCreators({fetchArticles}, dispatch)
    }
}

你应该使用

function mapDispatchToProps(dispatch) {
  return bindActionCreators({removeArticle, fetchArticles}, dispatch);
}
顾名思义,

bindActionCreators可以绑定多个动作创建者。

这可能不会解决你的问题,但答案是我唯一可以妥善解决这个问题的地方。

请注意,您还需要修复自己使用它的方式。没有更多的双重名字。

答案 1 :(得分:0)

我希望保留一个名为 shouldUpdateList 的状态。每当我触发更改列表的操作(将项目添加或更新到列表中)时,我将 shouldUpdateList 设置为 true 。然后,每当我触发ajax动作以获取列表时,将其设置回 false

我用来检查 shouldUpdateList 的生命周期事件是 componentWillReceiveProps ,如果它 true 我会触发获取操作。

编辑:我的意思是在Redux商店中保留 shouldUpdateList 状态。类似的东西:

const INIT_STATE = {
    list: [],
    shouldUpdateList: false
}

然后

case Action.ADD_NEW:
    //set shouldUpdateList to true
case Action.FETCH_LIST:
    //set shouldUpdateList to false

最后,在组件

componentWillReceiveProps(nextProps) {
    if(nextProps.shouldUpdateList === true) {
        //dispatch action FETCH_LIST
    }
}