React 中的 AJAX 请求:获取数据的方法与时机

lonelygift 8年前
   <p>React 新手一开始可能会问到这样一个问题,“在 React 中如何发送 AJAX 请求呢?”</p>    <p>本文正要回答该问题。</p>    <p>首先:React 本身对获取数据的方式并无任何特殊偏好。实际上,在 React 的图景中,根本就不知道“服务器”这种东西的存在。</p>    <p>React 只是使用 <strong>props</strong> 和 <strong>state</strong> 两处的数据进行组件渲染。</p>    <p>因此,想要使用来自服务端的数据,必须将数据放入组件的 props 或 state 中。</p>    <p>你完全可以按照喜好使用服务、数据模型(额,“建立抽象”)完成这个过程,但归根结底只不过是通过 props 和 state 渲染组件。</p>    <p>选择 HTTP 工具库</p>    <p>要从服务端拿到数据,首先得有一个 HTTP 工具库。现成的轮子数都数不清。它们最终做的事情都一样,但在一些特性上有所不同。</p>    <p>喜欢 Promise?那就试试 axios 吧。</p>    <p>不喜欢 Promise,对回调函数情有独钟?可以看一眼 superagent 。</p>    <p>要不试试将要成为标准的一些工具? <a href="/misc/goto?guid=4958972275802763497" rel="nofollow,noindex">fetch</a> 可能是你的菜。</p>    <p>这些其实根本不重要。没有“最佳”工具。</p>    <p>有些人可能会说, fetch 是最好的,因为 fetch 差不多已经是标准了。但我敢打赌,就算fetch <strong>真正</strong> 成为标准,还是会有人喜欢、使用一些与之匹敌的 HTTP 工具库。所以随你怎么选咯。</p>    <p>我个人比较喜欢 axios ,这也是本文示例所使用的。不过,认真的说,如果你偏偏不喜欢它,那就选其他的呗。</p>    <p>获取数据</p>    <p>下面是一个简单的示例组件,它从 Reddit 站点获取文章列表。先看一眼,后面会讲述代码是如何工作的。</p>    <pre>  <code class="language-javascript">import React from 'react';  import ReactDOM from 'react-dom';  import axios from 'axios';    class FetchDemo extends React.Component {    constructor(props) {      super(props);        this.state = {        posts: []      };    }      componentDidMount() {      axios.get(`http://www.reddit.com/r/${this.props.subreddit}.json`)        .then(res => {          const posts = res.data.data.children.map(obj => obj.data);          this.setState({ posts });        });    }      render() {      return (        <div>          <h1>{`/r/${this.props.subreddit}`}</h1>          <ul>            {this.state.posts.map(post =>              <li key={post.id}>{post.title}</li>            )}          </ul>        </div>      );    }  }    ReactDOM.render(    <FetchDemo subreddit="reactjs"/>,    document.getElementById('root')  );</code></pre>    <h3>如何工作</h3>    <p>首先引入 axios 。</p>    <pre>  <code class="language-javascript">import axios from 'axios';`</code></pre>    <p>constructor 方法非常标准,调用 super ,然后初始化 state,设置一个空的 posts 数组。</p>    <p>真正神奇的事情发生在 componentDidMount 方法中。组件首次“挂载”(mount)时,该方法就会执行。在组件生命周期中,该方法只会执行 <strong>一次</strong> 。</p>    <p>TL;DR: 在 componentDidMount 方法中获取服务端数据</p>    <p>componentDidMount 方法中,根据传入的 subreddit 属性,调用 axios.get 方法获取数据。反引号中是 ES6 模板字符串,可能如你所想, ${...} 部分会被其中表达式的值所替换,因此传给 axios.get 的 URL 实际上是 http://www.reddit.com/r/reactjs.json 。</p>    <p>此处需注意两点,和 Reddit 有关:</p>    <ul>     <li> <p>可以在 Reddit 网站下面所有的 URL 后面添加 .json 后缀,以获取 JSON 格式的内容。</p> </li>     <li> <p>如果去掉 www ,会产生 CORS 错误(至少我碰到了这个错误)。</p> </li>    </ul>    <p>因为 Axios 使用了 Promise,所以可以通过 .then 方法链式处理响应。经过一些处理后, posts 被提取出来了,紧接着是重点:</p>    <p>传入新的 posts 数组,使用 this.setState 方法更新组件状态。这会导致重新渲染,接下来文章列表就显示出来了。</p>    <p>这就是所有的一切啦哈哈!</p>    <h3>额外奖励:添加加载指示</h3>    <p>知道怎样修改代码,在请求尚未返回时添加一个 "Loading..." 消息吗?</p>    <p>提示:在 state 中设置一个标志,一旦请求完成则将其切换其值。在 render 函数中使用这个标志显示加载提示。</p>    <p>如果想看示例代码(包括加载提示以及附加的 error state ),可以点击 这里 下载可运行的例子,无需注册哟~</p>    <p>解压文件,依次执行 npm install 和 npm start 。示例基于棒棒哒 Create React App 创建。</p>    <p> </p>    <p>来自:http://www.zcfy.cc/article/ajax-requests-in-react-how-and-where-to-fetch-data-1348.html</p>    <p> </p>