2017-11-16 2 views
2

私は新しい投票を行うことができる簡単な投票アプリケーションを作成しようとしています。React/Nodeのコンポーネント全体を再レンダリングせずに 'Load More'機能を作成するにはどうすればいいですか?

「MyPolls」セクションでは、ポーリングのリスト全体をレンダリングする代わりに、最初に行った5つのポーリングのみをレンダリングします。

下部には[追加]ボタンがあり、クリックすると別の5つの投票などが読み込まれます。

私はMongoose/MongoDBバックエンドを使用していましたが、私のアプローチはskiplimitです。

私はこの機能を実装することができましたが、コンポーネント全体が再レンダリングされています。これは、「詳細をロード」ボタンを再度スクロールダウンする必要があるためです。

はここに私のアプリです:https://voting-app-drhectapus.herokuapp.com/

(使用することができます便宜のためにこれらのログインの詳細: ユーザ名:[email protected] パスワード:123

そしてMy Pollsページを後藤。

MyPoll.js

import React, { Component } from 'react'; 
import { connect } from 'react-redux'; 
import * as actions from '../../actions'; 

class MyPolls extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     skip: 0 
    }; 
    } 

    componentDidMount() { 
    this.props.fetchMyPolls(this.state.skip); 
    this.setState({ skip: this.state.skip + 5 }); 
    } 

    sumVotes(polls) { 
    return polls.reduce((a, b) => { 
     return a.votes + b.votes; 
    }); 
    } 

    loadMore(skip) { 
    this.props.fetchMyPolls(skip); 
    const nextSkip = this.state.skip + 5; 
    this.setState({ skip: nextSkip }); 
    } 

    renderPolls() { 
    return this.props.polls.map(poll => { 
     return (
     <div className='card' key={poll._id}> 
      <div className='card-content'> 
      <span className='card-title'>{poll.title}</span> 
      <p>Votes: {this.sumVotes(poll.options)}</p> 
      </div> 
     </div> 
    ) 
    }) 
    } 

    render() { 
    console.log('polls', this.props.polls); 
    console.log('skip:', this.state.skip); 
    return (
     <div> 
     <h2>My Polls</h2> 
     {this.renderPolls()} 
     <a href='#' onClick={() => this.loadMore(this.state.skip)}>Load More</a> 
     </div> 

    ); 
    } 
} 

function mapStateToProps({ polls }) { 
    return { polls } 
} 

export default connect(mapStateToProps, actions)(MyPolls); 

アクション作成者:

export const fetchMyPolls = (skip) => async dispatch => { 
    const res = await axios.get(`/api/mypolls/${skip}`); 

    dispatch({ type: FETCH_MY_POLLS, payload: res.data }); 
} 

投票ルート:

app.get('/api/mypolls/:skip', requireLogin, (req, res) => { 

    console.log(req.params.skip); 

    Poll.find({ _user: req.user.id }) 
     .sort({ dateCreated: -1 }) 
     .skip(parseInt(req.params.skip)) 
     .limit(5) 
     .then(polls => { 
     res.send(polls); 
     }); 
    }); 

全体GI thub repo:https://github.com/drhectapus/voting-app

私は、この機能を実装する方法が最善の解決策である可能性があることを理解しています。

+0

'あなたは' loadMore'方法で状態を更新するときMyPolls'コンポーネントは、レンダリングを再され、それがあるにonClick機能を変更することができますこれはより多くのポーリングを表示するため、望ましい動作です。望ましくないのは、URLの変更のために発生するスクロールアップです。 @forrertの回答は正しいものです:) – mario199

答えて

2

"More"リンクをクリックすると実際に反応ルータが新しいルートに移動し、MyPollsコンポーネント全体が再描画されるという事実によって、再レンダリングが引き起こされるようです。

<a href='#' onClick={...}><button onClick={...}>に置き換えてください。

あなたがbuttonを使用しない場合、あなたはまた

const onLoadMoreClick = e => { 
    e.preventDefault(); // this prevents the navigation normally occuring with an <a> element 
    this.loadMore(this.state.skip); 
} 
+0

これは良い答えです。私はhttps://codesandbox.io/s/mjz434j518でテストしました。私は同様の単​​純化されたユースケースを作り直し、まず 'preventDevault()'なしで試してみたところ、あなたのherokuappのように機能しました。それから私は 'preventDefault()'を追加し、それは魅力のように機能します:) – mario199

+0

excellent。ありがとうございました! – doctopus

関連する問題