fix a problem before:

  • in /tweets/api/views.py

    • tweet_list_view should apply pagination either

      1. @api_view(['GET'])
      2. def tweet_list_view(request, *args, **kwargs):
      3. qs = Tweet.objects.all()
      4. username = request.GET.get('username')
      5. if username != None:
      6. qs = qs.by_username(username)
      7. # serializer = TweetSerializer(qs, many=True)
      8. # return Response(serializer.data, status=200)
      9. return get_paginated_queryset_response(qs, request)

      and username divided list view is also paginated, such as http://localhost/api/tweets/?username=root
      image.png

Handling our New List View Response:

  • in /twittme-web/public/index.html

    • change data-username in div with id “tweetme-2” to a username with many tweets to do some tests later
    • (I kept “root” because that was my user with the most number of tweets) ```html

  1. <!--
  2. This HTML file is a template.
  3. If you open it directly in the browser, you will see an empty page.
  4. You can add webfonts, meta tags, or analytics to this file.
  5. The build step will place the bundled scripts into the <body> tag.
  6. To begin the development, run `npm start` or `yarn start`.
  7. To create a production bundle, use `npm run build` or `yarn build`.
  8. -->

  1. - in /twittme-web/src/tweets/list.js
  2. ```javascript
  3. //...
  4. export function TweetsList(props) {
  5. //...
  6. const [nextUrl, setNextUrl] = useState(null); //new
  7. //...
  8. useEffect(() => {
  9. if (tweetsDidSet === false) {
  10. const handleTweetListLookup = (response, status) => {
  11. if (status === 200) {
  12. setNextUrl(response.next); //new
  13. console.log(response)
  14. //setTweetsInit(response);
  15. setTweetsInit(response.results);
  16. setTweetsDidSet(true);
  17. } else {
  18. alert("There was an error");
  19. }
  20. };
  21. apiTweetList(props.username, handleTweetListLookup);
  22. }
  23. }, [tweetsInit, tweetsDidSet, setTweetsDidSet, props.username]);
  24. //...
  25. /*
  26. return tweets.map((item, index) => {
  27. return (
  28. <Tweet
  29. tweet={item}
  30. didRetweet={handleDidRetweet} //new
  31. className="my-5 py-5 border bg-white text-dark"
  32. key={`${index}-{item.id}`}
  33. />
  34. );
  35. });
  36. */
  37. return <React.Fragment>{tweets.map((item, index)=>{
  38. return <Tweet
  39. tweet={item}
  40. didRetweet={handleDidRetweet}
  41. className='my-5 py-5 border bg-white text-dark'
  42. key={`${index}-{item.id}`} />
  43. })}
  44. { nextUrl !== null && <button className='btn btn-outline-primary'>Load next</button>}
  45. </React.Fragment>
  46. }

runserver and npm start, access http://localhost:30/
image.png
The reactjs page only shows 20 tweets as the django feed view before, and if the user has over 20 tweets, there will be a button to the next page(not a functional button now).

Handling Pagination in React:

runserver and access http://localhost/api/tweets/?username=root, click next page url
image.png
url is changed, but contents are still tweets on the 1st page.
image.png
so the pagination is not actually applied on reactjs.

  • in /twittme-web/src/tweets/lookup.js

    • prepare to handle “nextUrl” in apiTweetList() ``javascript //export function apiTweetList(username, callback) { export function apiTweetList(username, callback, nextUrl) { let endpoint = "/tweets/" if(username){ endpoint =/tweets/?username=${username}` }

    if (nextUrl !== null && nextUrl !== undefined) { //new //endpoint = nextUrl.replace(“http://localhost:8000/api“, “”) endpoint = nextUrl.replace(“http://localhost/api“, “”)
    //endpoint becomes nextUrl without “http://localhost/api“ }

    backendLookup(“GET”, endpoint, callback); } ``` (becuase I met CORS problem here, so I changed “http://localhost:8000/api“ into “http://localhost/api“, and used chrome to access api page. )

  • in /twittme-web/src/tweets/list.js

    • write a method handleLoadNext to apply pagination and get into the next page
    • add onClick event on “Load next” to apply handleLoadNext ```javascript //… export function TweetsList(props) {

    const [tweetsInit, setTweetsInit] = useState([]); const [tweets, setTweets] = useState([]); const [nextUrl, setNextUrl] = useState(null);

    //…

    const handleLoadNext = (event) => { event.preventDefault() if (nextUrl !== null) {

    1. const handleLoadNextResponse = (response, status) =>{
    2. if (status === 200){
    3. setNextUrl(response.next) //prepare for the next page
    4. const newTweets = [...tweets].concat(response.results) //response.results is 20 tweets from the current page
    5. setTweetsInit(newTweets)
    6. setTweets(newTweets)
    7. } else {
    8. alert("There was an error")
    9. }
    10. }
    11. apiTweetList(props.username, handleLoadNextResponse, nextUrl) //append nextUrl here

    } }

    /* return (

    1. {tweets.map((item, index) => {
    2. return (
    3. <Tweet
    4. tweet={item}
    5. didRetweet={handleDidRetweet}
    6. className="my-5 py-5 border bg-white text-dark"
    7. key={`${index}-{item.id}`}
    8. />
    9. );
    10. })}
    11. {nextUrl !== null && (
    12. <button className="btn btn-outline-primary">Load next</button>
    13. )}

    ); */ return (

    1. {tweets.map((item, index) => {
    2. return (
    3. <Tweet
    4. tweet={item}
    5. didRetweet={handleDidRetweet}
    6. className="my-5 py-5 border bg-white text-dark"
    7. key={`${index}-{item.id}`}
    8. />
    9. );
    10. })}
    11. {nextUrl !== null && (
    12. <button onClick={handleLoadNext} className="btn btn-outline-primary">
    13. Load next
    14. </button>
    15. )}

    ); } ``` runserver and npm start to test, access http://localhost:30/
    click “Load next”
    image.png
    and we successfully get into the next page
    image.png
    until there are no enough next tweets
    image.png