繁体   English   中英

在所有页面中显示搜索查询结果

[英]displaying search query results in all pages

我使用 unsplash api 制作了一个图像搜索应用程序。 该应用程序包含分页,这就是问题所在。 当我搜索诸如花之类的东西时,它会在第一页显示花,但是当我将 go 转到第二页时,不再有花,而是由 componentDidMount 中的 fetchPhotos function 生成的默认照片,因为重新渲染我相信。 有没有一种方法可以让我在刷新页面之前查看所有页面中的搜索查询结果?

沙盒

应用程序.js

import React, { Component } from "react";
import Pagination from "./Pagination";
import List from "./List";
import "./styles.css";
import axios from "axios";

const LOAD_STATE = {
  SUCCESS: "SUCCESS",
  ERROR: "ERROR",
  LOADING: "LOADING"
};

const appId = "N1ZIgf1m1v9gZJhledpAOTXqS8HqL2DuiEyXZI9Uhsk";
const BASE_URL = "https://api.unsplash.com/photos?page=1";

export default class App extends Component {
  constructor() {
    super();
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.state = {
      photos: [],
      totalPhotos: 0,
      perPage: 5,
      currentPage: 1,
      loadState: LOAD_STATE.LOADING,
      search: ""
    };
  }
  handleChange(e) {
    this.setState({ search: e.target.value });
  }

  handleSubmit() {
    const { search, perPage } = this.state;
    console.log(search);
    const url =
      "https://api.unsplash.com/search/photos?page=1&query=" +
      search +
      "&client_id=" +
      appId;

    const options = {
      params: {
        client_id: appId,
        page: 1,
        per_page: perPage,
        order_by: "popularity"
      }
    };

    this.setState({ loadState: LOAD_STATE.LOADING });
    axios
      .get(url, options)
      .then(response => {
        console.log(typeof response.data);
        let photos;
        try {
          photos = response.data.results;
        } catch {
          photos = [];
        }
        this.setState({
          photos,
          totalPhotos: parseInt(response.headers["x-total"]),
          currentPage: 1,
          loadState: LOAD_STATE.SUCCESS
        });
      })
      .catch(() => {
        this.setState({ loadState: LOAD_STATE.ERROR });
      });
  }

  componentDidMount() {
    this.fetchPhotos(this.state.currentPage);
  }

  fetchPhotos(page) {
    var self = this;
    const { perPage } = this.state;

    const options = {
      params: {
        client_id: appId,
        page: page,
        per_page: perPage,
        order_by: "popularity"
      }
    };

    this.setState({ loadState: LOAD_STATE.LOADING });
    axios
      .get(BASE_URL, options)
      .then(response => {
        self.setState({
          photos: response.data,
          totalPhotos: parseInt(response.headers["x-total"]),
          currentPage: page,
          loadState: LOAD_STATE.SUCCESS
        });
      })
      .catch(() => {
        this.setState({ loadState: LOAD_STATE.ERROR });
      });
  }

  render() {
    return (
      <div className="app">
        <input
          onChange={this.handleChange}
          type="text"
          name="search"
          placeholder="Enter query"
        />
        <button type="submit" onClick={this.handleSubmit} className="button">
          Submit
        </button>
        <Pagination
          current={this.state.currentPage}
          total={this.state.totalPhotos}
          perPage={this.state.perPage}
          onPageChanged={this.fetchPhotos.bind(this)}
        />
        {this.state.loadState === LOAD_STATE.LOADING ? (
          <div className="loader" />
        ) : (
          <List data={this.state.photos} />
        )}
      </div>
    );
  }
}

分页

import React, { Component } from "react";

export default class Pagination extends Component {
  pages() {
    var pages = [];
    for (var i = this.rangeStart(); i <= this.rangeEnd(); i++) {
      pages.push(i);
    }
    return pages;
  }

  rangeStart() {
    var start = this.props.current - this.props.pageRange;
    return start > 0 ? start : 1;
  }

  rangeEnd() {
    var end = this.props.current + this.props.pageRange;
    var totalPages = this.totalPages();
    return end < totalPages ? end : totalPages;
  }

  totalPages() {
    return Math.ceil(this.props.total / this.props.perPage);
  }

  nextPage() {
    return this.props.current + 1;
  }

  prevPage() {
    return this.props.current - 1;
  }

  hasFirst() {
    return this.rangeStart() !== 1;
  }

  hasLast() {
    return this.rangeEnd() < this.totalPages();
  }

  hasPrev() {
    return this.props.current > 1;
  }

  hasNext() {
    return this.props.current < this.totalPages();
  }

  changePage(page) {
    this.props.onPageChanged(page);
  }

  render() {
    return (
      <div className="pagination">
        <div className="pagination__left">
          <a
            href="#"
            className={!this.hasPrev() ? "hidden" : ""}
            onClick={e => this.changePage(this.prevPage())}
          >
            Prev
          </a>
        </div>

        <div className="pagination__mid">
          <ul>
            <li className={!this.hasFirst() ? "hidden" : ""}>
              <a href="#" onClick={e => this.changePage(1)}>
                1
              </a>
            </li>
            <li className={!this.hasFirst() ? "hidden" : ""}>...</li>
            {this.pages().map((page, index) => {
              return (
                <li key={index}>
                  <a
                    href="#"
                    onClick={e => this.changePage(page)}
                    className={this.props.current == page ? "current" : ""}
                  >
                    {page}
                  </a>
                </li>
              );
            })}
            <li className={!this.hasLast() ? "hidden" : ""}>...</li>
            <li className={!this.hasLast() ? "hidden" : ""}>
              <a href="#" onClick={e => this.changePage(this.totalPages())}>
                {this.totalPages()}
              </a>
            </li>
          </ul>
        </div>

        <div className="pagination__right">
          <a
            href="#"
            className={!this.hasNext() ? "hidden" : ""}
            onClick={e => this.changePage(this.nextPage())}
          >
            Next
          </a>
        </div>
      </div>
    );
  }
}

Pagination.defaultProps = {
  pageRange: 2
};

问题在这里:

onPageChanged={this.fetchPhotos.bind(this)}

因为fetchPhotos不使用任何类型的查询来获取特定类型的照片,所以当页面更改时,您会得到默认响应。

您目前有两个功能可用于获取工作方式不同的照片。 您需要将代码重构为使用来自 state 的当前query的单个照片获取 function。

更新

像这样的东西:

fetchPhotos(page=1) {
    var self = this;
    const { search, perPage } = this.state;
    const url = `https://api.unsplash.com/search/photos?page=${page}&client_id=${appId}`
    const url = search ? `${url}&query=search` : url

    const options = {
      params: {
        client_id: appId,
        page: page,
        per_page: perPage,
        order_by: "popularity"
      }
    };

    this.setState({ loadState: LOAD_STATE.LOADING });
    axios
      .get(url, options)
      .then(response => {
        self.setState({
          photos: response.data,
          totalPhotos: parseInt(response.headers["x-total"]),
          currentPage: page,
          loadState: LOAD_STATE.SUCCESS
        });
      })
      .catch(() => {
        this.setState({ loadState: LOAD_STATE.ERROR });
      });
  }

然后你可以在 mount 上调用fetchPhotos并使用它来代替你的onSubmit ,看起来你可以摆脱它。

<button type="submit" onClick={this.fetchPhotos} className="button">
          Submit
        </button>

您的onPageChanged会获得一个 function 来获取默认照片。 您拥有的唯一一个基于动态输入/状态获取照片的 function 在您的handleSubmit中。 handleSubmit的主体提取到另一个变量中的箭头 function 中,并在 handleSubmit 中调用这个新提取的handleSubmit同时将这个新的 ZC1C425268E68385D1AB5074C17A94F14 传递给onPageChanged handleSubmitonPageChanged中留下相同的 API 调用

由于您使用的是 class 组件,因此将handleSubmit的主体提取为常量可能不是一个好主意。

而是将您的fetchPhotos方法重命名为fetchDefaultPhotos并将您的handleSubmit方法重命名为fetchPhotos以更好地表示每个方法的作用。

将新重命名的fetchPhotosonPageChanged并在您的componentDidMount中调用fetchDefaultPhotos 您还可以创建一个新的handleSubmit方法,该方法仅在需要时调用fetchPhotos

export default class App extends Component {
  constructor() {
    super();
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.state = {
      photos: [],
      totalPhotos: 0,
      perPage: 5,
      currentPage: 1,
      loadState: LOAD_STATE.LOADING,
      search: ""
    };
  }

  handleChange(e) {
    this.setState({ search: e.target.value });
  }

  handleSubmit(newPage) {
    this.fetchPhotos(newPage)
  }

  fetchPhotos(newPage) {
    const { search, perPage } = this.state;
    console.log(search);
    const url =
      "https://api.unsplash.com/search/photos?page=1&query=" +
      search +
      "&client_id=" +
      appId;

    const options = {
      params: {
        client_id: appId,
        page: 1,
        per_page: perPage,
        order_by: "popularity"
      }
    };

    this.setState({ loadState: LOAD_STATE.LOADING });
    axios
      .get(url, options)
      .then(response => {
        console.log(typeof response.data);
        let photos;
        try {
          photos = response.data.results;
        } catch {
          photos = [];
        }
        this.setState({
          photos,
          totalPhotos: parseInt(response.headers["x-total"]),
          currentPage: newPage,
          loadState: LOAD_STATE.SUCCESS
        });
      })
      .catch(() => {
        this.setState({ loadState: LOAD_STATE.ERROR });
      });
  }

  componentDidMount() {
    this.fetchDefaultPhotos(this.state.currentPage);
  }

  fetchDefaultPhotos(page) {
    var self = this;
    const { perPage } = this.state;

    const options = {
      params: {
        client_id: appId,
        page: page,
        per_page: perPage,
        order_by: "popularity"
      }
    };

    this.setState({ loadState: LOAD_STATE.LOADING });
    axios
      .get(BASE_URL, options)
      .then(response => {
        self.setState({
          photos: response.data,
          totalPhotos: parseInt(response.headers["x-total"]),
          currentPage: page,
          loadState: LOAD_STATE.SUCCESS
        });
      })
      .catch(() => {
        this.setState({ loadState: LOAD_STATE.ERROR });
      });
  }
}

更新

这是一个工作沙箱: https://codesandbox.io/s/so-op-sbx-6rnhu

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM