使用react-infinite-scroller创建待办事项列表

Umb*_*bro 3 javascript infinite-scroll reactjs

尝试使用创建待办事项列表react-infinite-scroller。该列表将显示20个待办事项,滚动时将显示下一个待办事项。我从' https://jsonplaceholder.typicode.com/todos ' 获取Todos 。提取的待办事项保存在todos变量中。

我已经为这个示例建模:https : //github.com/CassetteRocks/react-infinite-scroller/blob/master/docs/src/index.js

这里演示:https://cassetterocks.github.io/react-infinite-scroller/demo/

我看不到Loading..出现并获取其他任务。

代码在这里:https : //stackblitz.com/edit/react-tcm9o2?file=index.js

import InfiniteScroll from 'react-infinite-scroller';
import qwest from 'qwest';

class App extends Component {

  constructor (props) {
    super(props);
    this.state = {
      todos: [],
      hasMoreTodos: true,
      nextHref: null
    }
  }

  loadTodos(page){
     var self = this;
    const url = 'https://jsonplaceholder.typicode.com/todos';

    if(this.state.nextHref) {
      url = this.state.nextHref;
    }

    qwest.get(url, {
      linked_partitioning: 1,
      page_size: 10
    }, {
      cache: true
    })
    .then((xhr, resp) => {
      if(resp) {
        var todos = self.state.todos;
        resp.map((todo) => {

          todos.push(todo);
        });

        if(resp.next_href) {
          self.setState({
            todos: todos,
            nextHref: resp.next_href
          });
        } else {
          self.setState({
              hasMoreTodos: false
          });
        }
      }
    });
  }


  render () {
    const loader = <div className="loader">Loading ...</div>;
    console.log(this.state.todos);

    var items = [];
    this.state.todos.map((todo, i) => {
        items.push(
            <div className="track" key={todo.id}>
              <p className="title">{todo.title}</p>
            </div>
        );
    });


    return (
      <InfiniteScroll
            pageStart={0}
            loadMore={this.loadTodos.bind(this)}
            hasMore={this.state.hasMoreTodos}
            loader={loader}>
        <div className="tracks">
          {items}
        </div>
      </InfiniteScroll>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

我的问题更新

如何在代码中设置这些注释位置?

/*if(this.state.nextHref) {
    url = this.state.nextHref;
}*/

and

 /*if(resp.next_href) {
  self.setState({
    todos: todos,
    nextHref: resp.next_href
  });*/
Run Code Online (Sandbox Code Playgroud)

如何设置页面从1更改为2,然后从2更改为3?

class App extends Component {

  constructor (props) {
    super(props);
    this.state = {
      todos: [],
      hasMoreTodos: true,
      page: 1
    }
  }

  loadTodos(page){
    var self = this;

    const url = `/api/v1/project/tasks?expand=todos&filter%5Btype%5D=400&${page}&${per_page}`;

    /*if(this.state.nextHref) {
      url = this.state.nextHref;
    }*/

    axios.get(url, {
      'page': 1,
      'per-page': 10
    })
    .then(resp => {
      if(resp) {
        var todos = [self.state.todos, ...resp];

        /*if(resp.next_href) {
          self.setState({
            todos: todos,
            nextHref: resp.next_href
          });*/
        } else {
          self.setState({
              hasMoreTodos: false
          });
        }
      }
    });
  }


  render () {
    const loader = <div className="loader">Loading ...</div>;

    var divStyle = {
       'width': '100px';
       'height': '300px';
       'border': '1px solid black',
       'scroll': 'auto'
    };

    const items = this.state.todos.map((todo, i) => 
        <div className="track" key={todo.id}>
            <p className="title">{todo.title}</p>
        </div>);


    return (
        <div style={divStyle}>
            <InfiniteScroll
                pageStart={1}
                loadMore={this.loadTodos.bind(this)}
                hasMore={this.state.hasMoreTodos}
                loader={loader}>
            <div className="tracks">
                {items}
            </div>
            </InfiniteScroll>
        </div>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

更新2

代码在这里:https : //stackblitz.com/edit/react-4lwucm

import InfiniteScroll from 'react-infinite-scroller';
import axios from 'axios';

class App extends Component {
  constructor() {
    super();
    this.state = {
      todos: [],
      hasMoreTodos: true,
      page: 1,
      nextPage: 1,
      finishedLoading: false
    };
  }


  loadTodos = (id) => {
    if(!this.state.finishedLoading) {
      const params = {
        id: '1234',
        page: this.state.nextPage,
        'per-page': 10,
      }

      axios({
        url: `/api/v1/project/tasks`,
        method: "GET",
        params
      })
      .then(res => { 
        let {todos, nextPage} = this.state;

        if(resp) {    //resp or resp.data ????
          this.setState({
            todos: [...todos, ...resp], //resp or resp.data ????
            nextPage: nextPage + 1,
            finishedLoading: resp.length > 0 //resp or resp.data ????
          });
        }
      })
      .catch(error => {
        console.log(error);
      }) 
    }
  }

  render() {
    const loader = <div className="loader">Loading ...</div>;
    const divStyle = {
      'height': '300px',
      'overflow': 'auto',
      'width': '200px',
      'border': '1px solid black'
    }

   const items = this.state.todos.map((todo, i) => 
    <div className="track" key={todo.id}>
      <p className="title">{todo.title}</p>
    </div>);

    return (
      <div style={divStyle} ref={(ref) => this.scrollParentRef = ref}>
        <div>
            <InfiniteScroll
              pageStart={0}
              loadMore={this.loadTodos}
              hasMore={true || false}
              loader={<div className="loader" key={0}>Loading ...</div>}
              useWindow={false}
              getScrollParent={() => this.scrollParentRef}
            >
                {items}
            </InfiniteScroll>
        </div>
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

hug*_*ugo 5

编辑:我刚刚意识到您使用作为起点:

为什么一次获得所有东西

好吧,因为您的来源只是一个很大的JSON。

您正在使用的脚本中的逻辑适用于SoundCloud的API,该API分页(也就是逐块返回)庞大的列表。

您的API不会分页,因此为什么要一次接收所有内容。

查看SoundCloud API的示例结果:

{
    "collection": [
        {
            "kind": "track",
            "id": 613085994,
            "created_at": "2019/04/29 13:25:27 +0000",
            "user_id": 316489116,
            "duration": 476281,
            [...]
        },
        [...]
    ],
    "next_href": "https://api.soundcloud.com/users/8665091/favorites?client_id=caf73ef1e709f839664ab82bef40fa96&cursor=1550315585694796&linked_partitioning=1&page_size=10"
}
Run Code Online (Sandbox Code Playgroud)

中的URL next_href提供了下一批项目的URL(URL相同,但“ cursor”参数每次均不同)。这就是使无限列表起作用的原因:每次都获得下一批。

您必须实现服务器端分页才能实现此结果。

回应您的编辑:

我的问题更新

如何在代码中设置这些注释位置?

/*if(this.state.nextHref) {
    url = this.state.nextHref; }*/
Run Code Online (Sandbox Code Playgroud)

/*if(resp.next_href) {   self.setState({
    todos: todos,
    nextHref: resp.next_href   });*/
Run Code Online (Sandbox Code Playgroud)

忘记加载nextHref了,您没有。您所拥有的是当前页码(您已加载内容的页面)。

尝试以下方法:

if (!self.state.finishedLoading) {
  qwest.get("https://your-api.org/json", {
    page: self.state.nextPage,
    'per-page': 10,
  }, {
    cache: true
  })
  .then((xhr, resp) => {
    let {todos, nextPage} = self.state;

    if(resp) {
      self.setState({
        todos: [...todos, ...resp],
        nextPage: nextPage + 1,
        finishedLoading: resp.length > 0, // stop loading when you don't get any more results
      });
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

一些挑剔的人

除了具有副作用(并且仅针对该副作用self.state )之外,在这里您还在变异(坏Array.map):

    var todos = self.state.todos;
    resp.map((todo) => {
      todos.push(todo);
    });
Run Code Online (Sandbox Code Playgroud)

您可以将其编写为:

    var todos = [self.state.todos, ...resp];
Run Code Online (Sandbox Code Playgroud)

这里的地图用法相同:

var items = [];
this.state.todos.map((todo, i) => {
    items.push(
        <div className="track" key={todo.id}>
          <p className="title">{todo.title}</p>
        </div>
    );
});
Run Code Online (Sandbox Code Playgroud)

应写为:

const items = this.state.todos.map((todo, i) => 
    <div className="track" key={todo.id}>
      <p className="title">{todo.title}</p>
    </div>);
Run Code Online (Sandbox Code Playgroud)