在React中获取数据
React初學(xué)者經(jīng)常從不需要獲取數(shù)據(jù)的應(yīng)用開始。他們經(jīng)常面臨一個(gè)計(jì)數(shù)器,任務(wù)列表獲取井字棋游戲應(yīng)用。這是很好的,因?yàn)樵陂_始學(xué)習(xí)React的時(shí)候,數(shù)據(jù)獲取在你的應(yīng)用中添加了另一層復(fù)雜度。
然而,有些時(shí)候你想要從自己的或者第三方API請(qǐng)求真實(shí)世界的數(shù)據(jù)。這個(gè)文章給你一個(gè)怎么在React中獲取數(shù)據(jù)的演練。這沒有外部狀態(tài)管理的解決方案,像Redux或者M(jìn)obX參與存儲(chǔ)你獲取到的數(shù)據(jù)。相反你將要使用React的本地狀態(tài)管理。
內(nèi)容列表
- 在React組件樹的什么位置獲取數(shù)據(jù)?
- 如何在React中獲取數(shù)據(jù)?
- 怎么展示加載標(biāo)識(shí)和處理錯(cuò)誤呢?
- 如何在React中使用Axios獲取數(shù)據(jù)
- 在React怎么測(cè)試數(shù)據(jù)獲取?
- 怎么在React中使用Async/Await獲取數(shù)據(jù)?
- 如何在高階組件中獲取數(shù)據(jù)?
- 怎么在渲染屬性里獲取數(shù)據(jù)?
- 在React中怎么從GraphQL獲取數(shù)據(jù)?
在React組件樹的什么位置獲取數(shù)據(jù)?
想象你已經(jīng)有一個(gè)組件樹,在它的層級(jí)中有多個(gè)級(jí)別的組件。現(xiàn)在你將要從第三方API獲取一個(gè)列表項(xiàng)。現(xiàn)在,在你組件級(jí)別的哪個(gè)等級(jí),更精確的講,哪個(gè)特定組件,應(yīng)該獲取數(shù)據(jù)?這個(gè)基本上取決于三個(gè)標(biāo)準(zhǔn):
1.誰對(duì)這個(gè)數(shù)據(jù)感興趣?獲取數(shù)據(jù)的組件應(yīng)該是這些組件的公共父組件。
1. Who is interested in this data? The fetching component should be a common parent component for all these components.
+---------------+| || || || |+------+--------+|+---------+------------+| || |+-------+-------+ +--------+------+| | | || | | || Fetch here! | | || | | |+-------+-------+ +---------------+|+-----------+----------+---------------------+| | || | | +------+--------+ +-------+-------+ +-------+-------+ | | | | | | | | | | | | | I am! | | | | I am! | | | | | | | +---------------+ +-------+-------+ +---------------+||||+-------+-------+| || || I am! || |+---------------+2.當(dāng)異步請(qǐng)求數(shù)據(jù)的時(shí)候你想在哪里展示一個(gè)加載標(biāo)識(shí)(加載標(biāo)志,進(jìn)度條)? 根據(jù)第一個(gè)標(biāo)準(zhǔn),這個(gè)加載標(biāo)識(shí)可以展示在公共父組件中。然后這個(gè)公共父組件還是獲取數(shù)據(jù)的組件。
+---------------+| || || || |+------+--------+|+---------+------------+| || |+-------+-------+ +--------+------+| | | || | | || Fetch here! | | || Loading ... | | |+-------+-------+ +---------------+|+-----------+----------+---------------------+| | || | | +------+--------+ +-------+-------+ +-------+-------+ | | | | | | | | | | | | | I am! | | | | I am! | | | | | | | +---------------+ +-------+-------+ +---------------+||||+-------+-------+| || || I am! || |+---------------+**2.1.**但是當(dāng)加載標(biāo)識(shí)需要在更高級(jí)的組件中,數(shù)據(jù)獲取也需要被提升到這個(gè)組件中。
+---------------+| || || Fetch here! || Loading ... |+------+--------+|+---------+------------+| || |+-------+-------+ +--------+------+| | | || | | || | | || | | |+-------+-------+ +---------------+|+-----------+----------+---------------------+| | || | | +------+--------+ +-------+-------+ +-------+-------+ | | | | | | | | | | | | | I am! | | | | I am! | | | | | | | +---------------+ +-------+-------+ +---------------+||||+-------+-------+| || || I am! || |+---------------+2.2. 當(dāng)加載標(biāo)識(shí)應(yīng)該在公共父組件的每個(gè)子組件展示,不是每個(gè)子組件都需要數(shù)據(jù),公共父組件應(yīng)該還是獲取數(shù)據(jù)的組件。然后這個(gè)加載標(biāo)識(shí)狀態(tài)可以傳下來給那些感興趣,需要展示加載標(biāo)識(shí)的子組件。
+---------------+| || || || |+------+--------+|+---------+------------+| || |+-------+-------+ +--------+------+| | | || | | || Fetch here! | | || | | |+-------+-------+ +---------------+|+-----------+----------+---------------------+| | || | | +------+--------+ +-------+-------+ +-------+-------+ | | | | | | | | | | | | | I am! | | | | I am! | | Loading ... | | Loading ... | | Loading ... | +---------------+ +-------+-------+ +---------------+||||+-------+-------+| || || I am! || |+---------------+**3. 當(dāng)請(qǐng)求失敗的時(shí)候,你想在哪里展示可選的錯(cuò)誤信息?**這個(gè)和第二個(gè)加載標(biāo)識(shí)的標(biāo)準(zhǔn)使用一樣的規(guī)則。
這基本上就是在React組件層次結(jié)構(gòu)中獲取數(shù)據(jù)的所有內(nèi)容。但是什么時(shí)候獲應(yīng)該取數(shù)據(jù),一旦公共父組件達(dá)成一致應(yīng)該如何獲取數(shù)據(jù)?
如何在React中獲取數(shù)據(jù)?
React的ES6類組件有生命周期方法。render()生命周期方法強(qiáng)制返回一個(gè)React元素,因?yàn)楫吘鼓憧赡芟朐谀骋稽c(diǎn)展示獲取到的數(shù)據(jù)。
另一個(gè)生命周期方法是獲取數(shù)據(jù)的完美選擇:componentDidMount()。當(dāng)這個(gè)方法執(zhí)行的時(shí)候,這個(gè)組件已經(jīng)通過render()方法渲染了一次,但是將會(huì)在獲取數(shù)據(jù)并通過組件的setState()方法將數(shù)據(jù)存儲(chǔ)在本地后再次渲染。之后,本地狀態(tài)可以被render()方法使用去展示,或者通過props向下傳遞。
componentDidMount()生命周期方法是獲取數(shù)據(jù)最好的地方。但是怎么去獲取數(shù)據(jù)? React的生態(tài)系統(tǒng)是一個(gè)靈活的框架
從而你可以選擇你自己的方法去獲取數(shù)據(jù)。為了簡(jiǎn)單起見,這篇文章將會(huì)使用瀏覽器原生fetch API展示它。它使用了JavaScript promise作為異步函數(shù)的結(jié)果。這是獲取數(shù)據(jù)的最小示例,像下面這樣:
import React, { Component } from 'react';class App extends Component {constructor(props) {super(props);this.state = {data: null,};}componentDidMount() {fetch('https://api.mydomain.com').then(response => response.json()).then(data => this.setState({ data }));}... }export default App;這是一個(gè)最基本React.js fetch API的例子。這個(gè)例子向你展示了在React怎么從API中獲取JSON。然而,這邊文章將要演示怎么從一個(gè)真實(shí)世界中第三方API中獲取數(shù)據(jù)。
import React, { Component } from 'react';// ----------------------------------- const API = 'https://hn.algolia.com/api/v1/search?query='; const DEFAULT_QUERY = 'redux'; // -----------------------------------class App extends Component {constructor(props) {super(props);this.state = {// -----------------------------------hits: [],// -----------------------------------};}componentDidMount() {// -----------------------------------fetch(API + DEFAULT_QUERY)// -----------------------------------.then(response => response.json())// -----------------------------------.then(data => this.setState({ hits: data.hits }));// -----------------------------------}... }export default App;這個(gè)例子使用Hacker News API,但是你可以使用你自己的API。當(dāng)數(shù)據(jù)獲取成功,數(shù)據(jù)將通過React的 this.setState()方法被存在本地狀態(tài)中。然后 render方法將再次觸發(fā)并且你可以展示獲取到的數(shù)據(jù)。
...class App extends Component {...render() {const { hits } = this.state;return (<ul>{hits.map(hit =><li key={hit.objectID}><a href={hit.url}>{hit.title}</a></li>)}</ul>);} }export default App;即使render()方法已經(jīng)在 componentDidMount()方法之前執(zhí)行過一次,你不會(huì)遇到任何空指針異常,因?yàn)槟阍诒镜貭顟B(tài)里有一個(gè)初始的空數(shù)組hits屬性。
**注意:**如果你想知道怎么通過React Hooks特性獲取數(shù)據(jù),查看這個(gè)全面的指南如何在ReactHooks中獲取數(shù)據(jù)(翻譯)
怎么展示加載標(biāo)識(shí)和處理錯(cuò)誤呢?
當(dāng)然你需要獲取數(shù)據(jù)到你本地狀態(tài)。但是還有什么?這里還有兩個(gè)屬性你可以存儲(chǔ)在狀態(tài)里:加載狀態(tài)和錯(cuò)誤狀態(tài)。這些將提升你應(yīng)用的用戶體驗(yàn)。
加載狀態(tài)應(yīng)該用于指示一個(gè)異步請(qǐng)求在進(jìn)行中。在render()方法之間,由于異步到達(dá),獲取數(shù)據(jù)在等待中。從而你可以在等待期間添加一個(gè)加載標(biāo)識(shí)。在你獲取數(shù)據(jù)的生命周期方法里,你必須將這個(gè)屬性從false切換到true,當(dāng)數(shù)據(jù)被獲取到應(yīng)該從true切換到false。
...class App extends Component {constructor(props) {super(props);this.state = {hits: [],// -----------------------------------isLoading: false,// -----------------------------------};}componentDidMount() {// -----------------------------------this.setState({ isLoading: true });// -----------------------------------fetch(API + DEFAULT_QUERY).then(response => response.json())// -----------------------------------.then(data => this.setState({ hits: data.hits, isLoading: false }));// -----------------------------------}... }export default App;在你的render()方法里你可以使用React的條件渲染去展示加載標(biāo)識(shí)或者加載到的數(shù)據(jù)。
...class App extends Component {...render() {// -----------------------------------const { hits, isLoading } = this.state;// -----------------------------------// -----------------------------------if (isLoading) {return <p>Loading ...</p>;}// -----------------------------------return (<ul>{hits.map(hit =><li key={hit.objectID}><a href={hit.url}>{hit.title}</a></li>)}</ul>);} }一個(gè)加載標(biāo)識(shí)可以向Loading…消息一樣簡(jiǎn)單,但是你也可以使用第三方庫(kù)區(qū)展示一個(gè)標(biāo)識(shí)或者待定組件內(nèi)容。你可以通過信號(hào)通知用戶數(shù)據(jù)提取正在等待中。
你可以保持在你本地的第二個(gè)狀態(tài)將是一個(gè)錯(cuò)誤狀態(tài)。當(dāng)你的應(yīng)用中發(fā)生一個(gè)錯(cuò)誤,沒什么比不給用戶關(guān)于錯(cuò)誤的標(biāo)識(shí)更差的了。
...class App extends Component {constructor(props) {super(props);this.state = {hits: [],isLoading: false,// -----------------------------------error: null,// -----------------------------------};}...}使用promise的時(shí)候經(jīng)常在then()后面使用catch()塊去處理錯(cuò)誤。這就是為什么可以在原生的fetch API上使用catch()塊。
...class App extends Component {...componentDidMount() {this.setState({ isLoading: true });fetch(API + DEFAULT_QUERY).then(response => response.json()).then(data => this.setState({ hits: data.hits, isLoading: false }))// -----------------------------------.catch(error => this.setState({ error, isLoading: false }));// -----------------------------------}...}不幸的是,這個(gè)原生的fetch API不能使用catch塊捕獲每個(gè)錯(cuò)誤的狀態(tài)碼。例如,當(dāng)一個(gè)HTTP 404 發(fā)生了,并不會(huì)執(zhí)行到catch塊里。但是當(dāng)你沒有在結(jié)果中匹配到你希望的數(shù)據(jù)時(shí),你可以通過拋出一個(gè)錯(cuò)誤強(qiáng)制執(zhí)行到catch塊。
...class App extends Component {...componentDidMount() {this.setState({ isLoading: true });fetch(API + DEFAULT_QUERY)// -----------------------------------.then(response => {if (response.ok) {return response.json();} else {throw new Error('Something went wrong ...');}})// -----------------------------------.then(data => this.setState({ hits: data.hits, isLoading: false })).catch(error => this.setState({ error, isLoading: false }));}...}最后但也很重要的是,你可以再次通過條件渲染在你的render()方法展示一個(gè)錯(cuò)誤消息。
...class App extends Component {...render() {// -----------------------------------const { hits, isLoading, error } = this.state;// -----------------------------------// -----------------------------------if (error) {return <p>{error.message}</p>;}// -----------------------------------if (isLoading) {return <p>Loading ...</p>;}return (<ul>{hits.map(hit =><li key={hit.objectID}><a href={hit.url}>{hit.title}</a></li>)}</ul>);} }這就是使用簡(jiǎn)單的React獲取數(shù)據(jù)的基礎(chǔ)知識(shí)。你可以閱讀有關(guān)在React的本地狀態(tài)中管理所獲取數(shù)據(jù)的更多信息,或者在React中獨(dú)自管理狀態(tài)諸如Redux之類的庫(kù)。
如何在React中使用Axios獲取數(shù)據(jù)
就像已經(jīng)提到的,你可以使用其它庫(kù)替代原生的fetch API。例如,另一個(gè)庫(kù)可能每一個(gè)錯(cuò)誤的請(qǐng)求都會(huì)到catch塊中,不需要你自己向原先那樣拋出一個(gè)錯(cuò)誤。一個(gè)獲取數(shù)據(jù)好的選擇是axios庫(kù)。你可以通過npm install axios在你的項(xiàng)目中安裝axios,然后在你的項(xiàng)目中使用它替代原生的fetch API。讓我們使用axios取代原生的fetch API在React中獲取數(shù)據(jù)重構(gòu)上一個(gè)項(xiàng)目。
import React, { Component } from 'react'; // ----------------------------------- import axios from 'axios'; // -----------------------------------const API = 'https://hn.algolia.com/api/v1/search?query='; const DEFAULT_QUERY = 'redux';class App extends Component {constructor(props) {super(props);this.state = {hits: [],isLoading: false,error: null,};}componentDidMount() {this.setState({ isLoading: true });// -----------------------------------axios.get(API + DEFAULT_QUERY).then(result => this.setState({hits: result.data.hits,// -----------------------------------isLoading: false})).catch(error => this.setState({error,isLoading: false}));}... }export default App;就像你看到的,axios也返回了一個(gè)JavaScript promise對(duì)象。但是現(xiàn)在你不能解決這個(gè)promise兩次,因?yàn)閍xios已經(jīng)給你返回了一個(gè)JSON響應(yīng)。
此外,當(dāng)使用axios你可以確定所有錯(cuò)誤都會(huì)在catch()塊被捕捉。另外,你需要略微調(diào)整axios返回的數(shù)據(jù)結(jié)構(gòu)就行。
在上一個(gè)例子里向你展示了怎么在React的componentDidMount生命周期方法里通過一個(gè)HTTP的GET方法獲取數(shù)據(jù)。然而,你也可以通過一個(gè)按鈕的點(diǎn)擊來觸發(fā)請(qǐng)求。然后你不需要使用生命周期方法,但是你可以使用自己的類方法。
import React, { Component } from 'react'; import axios from 'axios';const API = 'https://hn.algolia.com/api/v1/search?query='; const DEFAULT_QUERY = 'redux';class App extends Component {constructor(props) {super(props);this.state = {hits: [],isLoading: false,error: null,};}// -----------------------------------getStories() {// -----------------------------------this.setState({ isLoading: true });axios.get(API + DEFAULT_QUERY).then(result => this.setState({hits: result.data.hits,isLoading: false})).catch(error => this.setState({error,isLoading: false}));}... }export default App;但是這只是React里的GET方法的使用。怎么通過API寫入數(shù)據(jù)?當(dāng)使用axios的時(shí)候,你也可以在React發(fā)送一個(gè)post請(qǐng)求。你也需要將axios.get()換成axios.post()。
在React怎么測(cè)試數(shù)據(jù)獲取?
所以怎么在React組件中測(cè)試數(shù)據(jù)獲取呢?這里有一個(gè)關(guān)于測(cè)試話題的廣泛的React測(cè)試教程,當(dāng)你使用create-react-app建立你的應(yīng)用,它已經(jīng)帶來了Jest測(cè)試框架和斷言庫(kù)。除此之外你也可以使用Mocha(測(cè)試框架)和Chai(斷言庫(kù))來實(shí)現(xiàn)這些目的(記住功能會(huì)因?yàn)闇y(cè)試框架和斷言庫(kù)而變化)
當(dāng)測(cè)試React組件的時(shí)候,在我的測(cè)試用例中,我經(jīng)常依賴Enzyme去渲染組件。此外,當(dāng)測(cè)試異步數(shù)據(jù)獲取,Sinon有助于檢查和模擬數(shù)據(jù)。
npm install enzyme enzyme-adapter-react-16 sinon --save-dev首先你有你的測(cè)試體系,你可以在React腳本中寫你第一個(gè)數(shù)據(jù)獲取的測(cè)試套件
import React from 'react'; import axios from 'axios';import sinon from 'sinon'; import { mount, configure} from 'enzyme'; import Adapter from 'enzyme-adapter-react-16';import App from './';configure({ adapter: new Adapter() });describe('App', () => {beforeAll(() => {});afterAll(() => {});it('renders data when it fetched data successfully', (done) => {});it('stores data in local state', (done) => {}); });而一個(gè)測(cè)試用例應(yīng)該在數(shù)據(jù)獲取后在React組件成功渲染數(shù)據(jù),提測(cè)測(cè)試用例驗(yàn)證數(shù)據(jù)被存儲(chǔ)在本地狀態(tài)里。或許測(cè)試兩種情況是冗余的,因?yàn)楫?dāng)數(shù)據(jù)被渲染了,那么數(shù)據(jù)也應(yīng)該被存在本地狀態(tài)里了,但是只是為了展示,你會(huì)看到兩個(gè)用例。
在所有測(cè)試之前,你希望使用模擬數(shù)據(jù)來存儲(chǔ)您的axios請(qǐng)求。你可以為請(qǐng)求創(chuàng)建自己的JavaScript promise 并且之后可以使用它細(xì)膩的控制promise的解決。
...describe('App', () => {const result = {// -----------------------------------data: {hits: [{ objectID: '1', url: 'https://blog.com/hello', title: 'hello', },{ objectID: '2', url: 'https://blog.com/there', title: 'there', },],}};// -----------------------------------const promise = Promise.resolve(result);beforeAll(() => {// -----------------------------------sinon.stub(axios, 'get').withArgs('https://hn.algolia.com/api/v1/search?query=redux').returns(promise);// -----------------------------------});afterAll(() => {// -----------------------------------axios.get.restore();// -----------------------------------});... });在所有測(cè)試之后你應(yīng)該再次確認(rèn)移除了所有axios的存根。這句是異步數(shù)據(jù)獲取測(cè)試的建立。現(xiàn)在讓我們實(shí)現(xiàn)第一個(gè)測(cè)試:
...describe('App', () => {...it('stores data in local state', (done) => {const wrapper = mount(<App />);expect(wrapper.state().hits).toEqual([]);promise.then(() => {wrapper.update();expect(wrapper.state().hits).toEqual(result.data.hits);done();});});... });在測(cè)試中,你通過Enzyme的mount()函數(shù)開始渲染React組件,這個(gè)方法確保所有生命生命周期方法執(zhí)行,并且所有子組件被渲染。
最初你可以在你組件本地狀態(tài)的hit是一個(gè)空數(shù)組的時(shí)候有一個(gè)斷言。這應(yīng)該是正確的,因?yàn)槟阃ㄟ^一個(gè)空數(shù)組初始化你的本地狀態(tài)的hits屬性。首先你解決了promise并且手動(dòng)觸發(fā)了組件的渲染,這個(gè)狀態(tài)應(yīng)該在數(shù)據(jù)獲取后改變。
接下來,你可以測(cè)試所有內(nèi)容是否相應(yīng)呈現(xiàn)。這個(gè)測(cè)試和之前測(cè)試很像。
...describe('App', () => {...it('renders data when it fetched data successfully', (done) => {const wrapper = mount(<App />);expect(wrapper.find('p').text()).toEqual('Loading ...');promise.then(() => {wrapper.update();expect(wrapper.find('li')).toHaveLength(2);done();});}); });在測(cè)試開始前,加載中標(biāo)識(shí)應(yīng)該被渲染。再次,一旦你解決了promise并且手動(dòng)觸發(fā)組件的渲染,應(yīng)該有兩個(gè)列表元素用于請(qǐng)求數(shù)據(jù)。
這些基本上就是React中關(guān)于數(shù)據(jù)獲取測(cè)試你需要知道的。它不需要復(fù)雜。當(dāng)有自己的promise,你可以精細(xì)控制合適解決promise和更新組件。之后你可以進(jìn)行斷言。之前展示的測(cè)試場(chǎng)景只是一個(gè)方法。例如,關(guān)于測(cè)試工具你不一定需要使用Sinon和Enzyme。
怎么在React中使用Async/Await獲取數(shù)據(jù)?
至今,你只通過通用的方法then()和catch()塊去處理JavaScript promise。使用JavaScript中下一代異步請(qǐng)求怎么樣?讓我們使用async/await重構(gòu)上一個(gè)數(shù)據(jù)獲取的例子。
import React, { Component } from 'react'; import axios from 'axios';const API = 'https://hn.algolia.com/api/v1/search?query='; const DEFAULT_QUERY = 'redux';class App extends Component {...// -----------------------------------async componentDidMount() {// -----------------------------------this.setState({ isLoading: true });// -----------------------------------try {const result = await axios.get(API + DEFAULT_QUERY);// -----------------------------------this.setState({hits: result.data.hits,isLoading: false});// -----------------------------------} catch (error) {// -----------------------------------this.setState({error,isLoading: false});// -----------------------------------}// -----------------------------------}... }export default App;當(dāng)在React中獲取數(shù)據(jù)的時(shí)候你可以使用async/await語(yǔ)句取代then()。async語(yǔ)句用于表示函數(shù)是異步執(zhí)行的。它也可以使用在(React)類組件的方法上。await語(yǔ)句是在async函數(shù)內(nèi)部每當(dāng)執(zhí)行異步函數(shù)時(shí)使用的。所以在等待的請(qǐng)求解決前下一行是不會(huì)執(zhí)行的。此外,如果請(qǐng)求失敗,一個(gè)try catch塊可以用于捕獲錯(cuò)誤。
如何在高階組件中獲取數(shù)據(jù)?
在許多組件中使用它時(shí),之前展示的獲取數(shù)據(jù)的方法可以復(fù)用。一旦一個(gè)組件掛載,你想去獲取數(shù)據(jù)并且展示條件加載標(biāo)識(shí)和錯(cuò)誤標(biāo)識(shí)。這個(gè)組件入境可以分出兩個(gè)職責(zé):通過條件渲染展示獲取到的數(shù)據(jù)和獲取到遠(yuǎn)程數(shù)據(jù)之后存在本地狀態(tài)里。而前者只用于渲染目的,后者可以通過高階組件被重用。
注意:當(dāng)你要去閱讀鏈接的文章,你也將會(huì)看到你怎么在高階組件中抽象條件渲染。在那之后,你的組件將只關(guān)心展示獲取到的數(shù)據(jù),沒有任何條件渲染。
所以你怎樣引入抽象高階組件處理在React中的數(shù)據(jù)獲取。首先你將會(huì)分離所有獲取和存儲(chǔ)邏輯到高階組件中。
const withFetching = (url) => (Component) =>class WithFetching extends React.Component {constructor(props) {super(props);this.state = {data: null,isLoading: false,error: null,};}componentDidMount() {this.setState({ isLoading: true });axios.get(url).then(result => this.setState({data: result.data,isLoading: false})).catch(error => this.setState({error,isLoading: false}));}render() {return <Component { ...this.props } { ...this.state } />;}}除了渲染,高階組價(jià)中每個(gè)其他部分都取自上一個(gè)組件的數(shù)據(jù)正確提取的部分。另外,高階組件使用接受到的一個(gè)url獲取請(qǐng)求數(shù)據(jù)。如果你需要傳遞更多參數(shù)給告誡組件,你也可以擴(kuò)展函數(shù)簽名的參數(shù)列表。
const withFetching = (url, query) => (Comp) =>...另外,告誡組件使用一個(gè)名叫data的通過用數(shù)據(jù)包裹本地狀態(tài)。它不再像之前一樣了解具體的屬性名(e.g hits)
第二步,你可以部署所有來自你的App組件的數(shù)據(jù)獲取和狀態(tài)邏輯,因?yàn)樗僖矝]有本地狀態(tài)和生命周期方法。你可以通過函數(shù)式無狀態(tài)組件重用它。傳入的屬性從特定命名改為通用數(shù)據(jù)屬性。
const App = ({ data, isLoading, error }) => {if (!data) {return <p>No data yet ...</p>;}if (error) {return <p>{error.message}</p>;}if (isLoading) {return <p>Loading ...</p>;}return (<ul>{data.hits.map(hit =><li key={hit.objectID}><a href={hit.url}>{hit.title}</a></li>)}</ul>); }最后但也很重要的是,你可以使用高階組件區(qū)包裹你的App組件。
const API = 'https://hn.algolia.com/api/v1/search?query='; const DEFAULT_QUERY = 'redux';...const AppWithFetch = withFetching(API + DEFAULT_QUERY)(App);基本上這就是在React中的抽離數(shù)據(jù)獲取。通過使用告誡組件去獲取數(shù)據(jù),你可以輕松配置任何需要url獲取數(shù)據(jù)的任何組件。另外,你可以擴(kuò)展它通過查詢參數(shù)就像之前展示過得。
#怎么在渲染屬性里獲取數(shù)據(jù)?
在React中可以在高階組件和渲染屬性里二選一。在React中使用渲染屬性去數(shù)據(jù)獲取也是可以的。
class Fetcher extends React.Component {constructor(props) {super(props);this.state = {data: null,isLoading: false,error: null,};}componentDidMount() {this.setState({ isLoading: true });axios.get(this.props.url).then(result => this.setState({data: result.data,isLoading: false})).catch(error => this.setState({error,isLoading: false}));}render() {return this.props.children(this.state);} }然后你可以再次向下面這樣在你的App組件中使用渲染屬性。
const API = 'https://hn.algolia.com/api/v1/search?query='; const DEFAULT_QUERY = 'redux';...const RenderPropApproach = () =><Fetcher url={API + DEFAULT_QUERY}>{({ data, isLoading, error }) => {if (!data) {return <p>No data yet ...</p>;}if (error) {return <p>{error.message}</p>;}if (isLoading) {return <p>Loading ...</p>;}return (<ul>{data.hits.map(hit =><li key={hit.objectID}><a href={hit.url}>{hit.title}</a></li>)}</ul>);}}</Fetcher>通過使用React的children屬性作為渲染蘇醒,你也可以從Fetcher組件傳遞所有本地狀態(tài)。這就是你讓所有條件渲染和最終渲染在你的屬性渲染中的辦法。
在React中怎么從GraphQL獲取數(shù)據(jù)?
最后但也很重要的是,這篇文章應(yīng)該很快提到React的GraphQL API。在React組件中你怎么用使用GraphQL API取代REST API獲取數(shù)據(jù)(如今你使用的是哪個(gè))?基本上它可以以同樣的方式實(shí)現(xiàn),因?yàn)镚raphQL對(duì)網(wǎng)絡(luò)層沒有要求。大多數(shù)GraphQL API都是通過HTTP公開的,無論是否使用原生的fetch API還是axios進(jìn)行查詢。如果你感興趣在React中如何通過GraphQL API獲取數(shù)據(jù),前往這篇文章:A complete React with GraphQL Tutorial。
你可以在這個(gè)github倉(cāng)庫(kù)找到完成的項(xiàng)目。你還有對(duì)于React中數(shù)據(jù)獲取的建議嗎?請(qǐng)聯(lián)系我。你將這篇文章分享給其他學(xué)習(xí)如何在React中獲取數(shù)據(jù)的人對(duì)我很有意義。
總結(jié)
以上是生活随笔為你收集整理的在React中获取数据的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: React hook 中的数据获取
- 下一篇: babel6和babel7中关于poly