如何从React组件更改Express上的API URL

时间:2019-06-07 23:18:42

标签: javascript json reactjs

我具有以下外部JSON API:

{
  "products": [
    {
      "id": 1,
      "name": "Product Number 1",
    },
    {
      "id": 2,
      "name": "Product Number 2",
    },
    {
      "id": 3,
      "name": "Product Number 3",
    }
  ],
  "nextPage": "someapiurl.com/products?page=2"
}

API上的nextPage链接具有与上面相同的结构,但是具有不同的产品和指向第3页的链接。然后,第4、5、6,...页具有相同的结构。

我正在将其获取到Express服务器,并使用代理在React上使用数据。

这是我拥有的快递服务器:

const express = require('express');
const fetch = require('node-fetch');
const path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, 'build')));

app.get('/api', (req, res) => {
    let url = 'someapiurl/products?page=1';
    fetch(url).then((response) => response.json()).then((contents) =>
        res.send({
            products: contents.products,
            nextPage: contents.nextPage
        })
    );
});

app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.listen(process.env.PORT || 8080);

然后是我的react组件:

import React, { useEffect, useState } from 'react';
import fetch from 'node-fetch';

const IndexPage = () => {
    const [ products, setProducts ] = useState([]);
    const [ nextPage, setNextPage ] = useState('');

    useEffect(() => {
        const url = '/api';
        fetch(url).then((response) => response.json()).then((contents) => {
            setProducts([ ...products, ...contents.products ]);
            setNextPage(contents.nextPage);
        });
    }, []);
    return (
        <div>
            {products.map((product) => <p>{product.name}</p>)}
            <button>Load More</button>
        </div>
    );
};

export default IndexPage;

我期望的是,当我单击“加载更多”时,发送状态nextPage进行表达,然后更改变量url。我的意图是将API第二页上的产品添加到产品状态,然后呈现到页面上。

如果更好,我可以将其更改为axios以查询数据。

2 个答案:

答案 0 :(得分:0)

请参见以下示例:

class Feed extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      items: [],
      visible: 2,
      error: false
    };

    this.loadMore = this.loadMore.bind(this);
  }

  loadMore() {
    this.setState((prev) => {
      return {visible: prev.visible + 4};
    });
  }

  componentDidMount() {
    fetch("https://jsonplaceholder.typicode.com/posts").then(
      res => res.json()
    ).then(res => {
      this.setState({
        items: res
      });
    }).catch(error => {
      console.error(error);
      this.setState({
        error: true
      });
    });
  }

  render() {
    return (
      <section>
        <div>
          {this.state.items.slice(0, this.state.visible).map((item, index) => {
              return (
                <div key={item.id}>
                  <span>{index+1}</span>
                  <h2>{item.title}</h2>
                  <p>{item.body}</p>
                </div>
              );
            })}
          </div>
          {this.state.visible < this.state.items.length &&
             <button onClick={this.loadMore} type="button">Load more</button>
          }
        </section>
    );
  }
}

ReactDOM.render(<Feed />, document.getElementById('feed'));

答案 1 :(得分:0)

根据React文档,componentDidMount生命周期方法是加载一些初始数据的好地方。

  

componentDidMount

     

... 如果您需要从远程端点加载数据,这是实例化网络请求的好地方...   您可以立即在componentDidMount()中调用setState()。它会触发额外的渲染,但是会在浏览器更新屏幕之前发生...

因此这是您获取第一个产品页面的地方。例如。 someapiurl.com/products?page=1 您可能还需要将下一页(nextPage)值设置为nextPage状态属性。 也许是这样的:

componentDidMount() {
  fetch('someapiurl.com/products?page=1')
    .then(response => response.json())
    .then(json => {
       this.setState({
         products: json.products
         nextPage: json.nextPage
       })
    })
}

现在,您可以根据products状态属性来渲染产品。

return (
  <React.Fragment>
    <ul>{ this.state.products.map( product => (<li key={product.id}>{product.name}</li>) ) } </ul>
    <button onClick={this.onNextPageClick}>next</button>
  </React.Fragment>
);

使用button调用函数以加载下一页,然后将更改productsnextPage状态属性。也许只需添加一个函数来获取数据,然后将nextPage URL传递给它即可。

loadNextPage = url => {
    fetch(url)
    .then(response => response.json())
    .then(json => {
       this.setState({
         products: json.products
         nextPage: json.nextPage
       })
    })
}

因此,每当单击按钮时,onNextPageClick处理程序将调用loadNextPage当前设置为任何值的this.state.nextPage

onNextPageClick = event => {
    this.loadNextPage(this.state.nextPage)
}

您可能还想看看Introducing Hooks

React钩子使您无需使用类或生命周期方法即可完成上述所有操作。

  

Hooks at a Glance

     

挂钩是React 16.8中的新增功能。它们使您无需编写类即可使用状态和其他React功能。

这里是一个使用React挂钩的示例,您可以根据需要进行调整。它只是通过增加每次点击的值来加载username。由于我没有任何页面,因此我认为这会模仿您的情况。我相信你会明白的。

function LoadStuff () {

  const [userId, setUserId] = React.useState(1);
  const [userName, setUserName] = React.useState("")

  const fetchUser = url => {
    fetch(url)
      .then(response => response.json())
      .then(json => {
      setUserName(json.name)
    })
  }

  React.useEffect(() => {
    fetchUser('https://jsonplaceholder.typicode.com/users/'+userId)
  }, [userId])

  const loadNextUser = () => (userId < 10) ? setUserId(userId + 1) : setUserId(1)

  return (
    <React.Fragment>
      <div>
        <p>{userId}</p>
        <p>{userName}</p>
      </div>
      <button onClick={loadNextUser}>Load next user</button>
    </React.Fragment>
  );

}

ReactDOM.render(
  <LoadStuff />,
  document.getElementById('container')
);
<script src="https://unpkg.com/react@16.8.6/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.8.6/umd/react-dom.development.js"></script>

<div id="container">
  <!-- This element's contents will be replaced with your component. -->
</div>