發(fā)布于:2021-02-19 00:02:20
0
265
0
從字面上看,自啟動React以來,我所有的項(xiàng)目都是基于Pokemon或使用Pokemon藝術(shù)。她可能喜歡神奇寶貝嗎?
通過編碼我發(fā)現(xiàn)了一件奇怪的事情,那就是對數(shù)據(jù)進(jìn)行排序很有趣?碰巧pokemon包含了許多有趣的數(shù)據(jù)小道消息,可以進(jìn)行排序,并與其他內(nèi)容進(jìn)行匹配。所以,我再一次使用了一個API和一些pokemon,但是這次我們使用的是Reddit的API。
目標(biāo)
從各個子Reddits獲取數(shù)據(jù)
了解Reddit的api術(shù)語是什么
顯示pokemon在標(biāo)題和帖子中提到的內(nèi)容
通過pokemon的交易進(jìn)行搜索
我們都得到了嗎?讓我們看看發(fā)生了什么。
Reddit?
Reddit是互聯(lián)網(wǎng)上的一個地方,由用戶運(yùn)行的subreddit組成。每樣?xùn)|西都有一個子項(xiàng),事實(shí)上,可能每樣?xùn)|西都有不同的規(guī)則。對于這個項(xiàng)目,我想subreddits是專門用于交易的口袋妖怪,是經(jīng)常更新,并使用類似的預(yù)修復(fù)。對于我選擇的三個子項(xiàng),它們在大多數(shù)查找中都使用LF(尋找)和FT(交易)。現(xiàn)在我們繼續(xù)討論如何使用reddit的api。我們來分析一下我的第一個電話。
axios.get(`https://www.reddit.com/r/pokemontrades/search.json?q=LF&q=FT&limit=30&restrict_sr=1&sort=new`)
簡單部分:
`https://www.reddit.com/r/pokemontrades/search.json?`
我們通過reddit,然后指定子reddit,然后啟動一個搜索,得到一個包含所有信息的.json文件。
`/search.json?q=LF&q=FT`
我們問兩個搜索問題。里面有LF嗎?它包含F(xiàn)T嗎?如果有那么好的話。我們也無法查詢和獲取所有帖子,但如果有不符合格式的問題或mod更新,我們希望將其剔除。
`limit=30&restrict_sr=1`
有一個更嚴(yán)格的限制是100個,但我真的不希望人們通過300個條目,所以我們只會拉30個subreddit,共90個上市。限制的好處是,這都是一個api調(diào)用!下一部分,我們將搜索限制到我們定義的特定子項(xiàng)。為什么?我不知道。如果您不這樣做,它會在所有子項(xiàng)中顯示出來,這是我們真正不需要的。
`&sort=new`
如果你熟悉reddit,這個很簡單。Reddit有各種模式可以按時間的頂端排序,按當(dāng)前時間的熱點(diǎn)排序,然后按最新的排序,等等。我們想要最新的交易,所以我們想要的不是相關(guān)性,而是最新的。
這些數(shù)據(jù)是什么?
很多。不幸的是,這還不夠。我們可以遍歷數(shù)據(jù),進(jìn)入被請求的30個孩子并獲得大量數(shù)據(jù)!我們可以獲取帖子標(biāo)題,正文,風(fēng)格,mod操作和...
不是日期?
創(chuàng)建字段的日期是發(fā)出請求的日期。正如我剛剛要求的那樣,所以這是創(chuàng)建日期或utc。根據(jù)我的研究,沒有為api提供可用的時間戳記。這給我的計(jì)劃帶來了麻煩。
原計(jì)劃
我打算使用查詢來查找pokemon相關(guān)的條目!因此,我們不使用常規(guī)查詢,而是使用以下內(nèi)容:
axios.get(`https://www.reddit.com/r/pokemontrades/search.json?q=Vulpix&limit=30&restrict_sr=1&sort=new`)
這確實(shí)有效。它將收集所有能找到的關(guān)于vulpix的帖子,最多30篇。不過,有些已經(jīng)有幾個月大了。雖然我有過簡單地提供數(shù)據(jù)的實(shí)踐,但作為一種更靜態(tài)的資源,我希望它至少有點(diǎn)有用。當(dāng)然,我可以搜索特定的pokemon,但是沒有一個截止日期的方法,它只是白噪音,使它看起來更強(qiáng)大,然后有用。
新計(jì)劃
緩存數(shù)據(jù)!我們的內(nèi)容一旦是動態(tài)的,就不會像本地瀏覽器中的緩存那樣,而是接受我們最初的調(diào)用并使用這些數(shù)據(jù)。因此,與其找一些關(guān)于pokemon的老東西,不如看看最新的90條帖子中提到了哪個pokemon。
return general.map((listing, i) => { let post = listing.data; let pkmnMentioned = this.getPKMNMentioned(post); if (pkmnMentioned.includes(pokemon, i)) { return <Entry key={post.title + i} subName={post.subreddit_name_prefixed} title={post.title} url={post.url} text={post.selftext} searchPokemon={this.state.searchPokemon} setSpecificAndPokemon={this.setSpecificAndPokemon} />; } else { return ""; } });
關(guān)鍵是要使用一個唯一的標(biāo)識符,這是原來的標(biāo)題本身不是,因?yàn)樵跍y試期間有人雙重張貼,它真的搞砸了我的渲染。吸取的教訓(xùn)。searchPokemon是一個狀態(tài)變量,它保存了我們當(dāng)前正在搜索的pokemon,因此我們可以向下傳遞它并突出顯示我們正在搜索的精靈。如果我們正在搜索一個特定的口袋妖怪或者沒有,我們也會傳遞設(shè)置這個狀態(tài)和布爾值的能力。
我最初讓Entry組件來確定提到了哪個pokemon,但是就像React一樣,您通常會找到一個理由來提升處理級別。上面提到的getpkmn只是通過pokemonArray(一個包含所有pokemon的數(shù)組,說真的,它很長)搜索標(biāo)題和自我文本(body),看看pokemon是否出現(xiàn)在它的數(shù)據(jù)中。Search返回?cái)?shù)據(jù)所在位置的數(shù)字,如果數(shù)據(jù)不在其中則返回-1,因此我們只需查看該數(shù)字是否大于-1即可推送到pokmemon提到的數(shù)組。由于大部分提到都是在身體里進(jìn)行的,所以我決定先這樣做,如果身體沒有返回特定的口袋妖怪,它會在標(biāo)題中搜索口袋妖怪,這樣我們就不會加倍并掩蓋我們的基礎(chǔ)。
{this.state.general[89] ? listings : "Loading..."}
作為一個簡短的說明,因?yàn)槲覀冎牢覀冎凰阉髁?0個條目,所以我們可以用它來確定我們是否完成了加載我們所做的三個調(diào)用。我喜歡這個api。一張紙條一張紙條,我其實(shí)不寫此.state.value對于所有的事情,我只是在文章代碼中有它,這樣你就可以看到發(fā)生了什么。我應(yīng)該做一個更復(fù)雜的加載動畫,但它似乎太瑣碎相比,它實(shí)際上需要多長時間加載。
條目組件
因?yàn)槲覀儼裵okemon的搜索從我們的條目中刪除了(或者更確切地說,我在寫這篇文章的時候忘了把它刪除,謝謝您查看代碼!)是相當(dāng)稀疏的。最重要的一點(diǎn)是,我們的圖像名稱擺脫了特殊的字符和斬首他們,所以我們必須做一點(diǎn)正則表達(dá)式的魔力,使之工作。一點(diǎn)額外的魔力,將自我文本中的內(nèi)容變回一個
import React from 'react'; import Sprite from './Sprite'; export default function Entry(props) { props.pkmnMentioned.forEach(pokemon => { let spriteName = pokemon .replace(/s+/g, '-') .replace(/[.,':s]/g, "") .replace(/♀/g, "-f") .replace(/♂/g, "-m") .toLowerCase(); spritesMentioned.push( <Sprite key={pokemon} fullName={pokemon} name={spriteName} isSearched={pokemon === props.searchPokemon} setSpecificAndPokemon={props.setSpecificAndPokemon} /> ); }) return ( <div className="entry"> <div className="subname">{props.subName}</div> <a href={props.url} target="_blank" rel="noopener noreferrer" className="title" > {props.title.replace(/(&)/g, "&")} </a> <div className="sprites-container"> <h3>Pokemon Mentioned:</h3> <div className="sprites"> {spritesMentioned.length ? spritesMentioned : "None"} </div> </div> </div> ); }
rel=“noopener或noreferrer”
讓我們花點(diǎn)時間來確認(rèn)我所做的事情,因?yàn)槿绻也贿@樣做,React會對我大喊大叫。如果我在目標(biāo)空白處打開,React會告訴我,在沒有rel=“noopener noreferrer”的情況下這樣做會有安全風(fēng)險。讓我用谷歌搜索一下,也許我們都會學(xué)到一些新東西。
我們鏈接到的頁面通過開窗器“對象”。因此,可以在看起來合法的鏈接上插入javascript來重定向到一個不好的站點(diǎn)。這篇文章中最有趣的部分是,谷歌只是接受了這一點(diǎn),認(rèn)為這是“當(dāng)前網(wǎng)頁瀏覽器設(shè)計(jì)的固有特點(diǎn),任何一個網(wǎng)站都無法有效緩解”。
精靈組件
比條目更小的是Sprite組件。只需將它插入到條目中,而不是它自己的組件是可能的,但我覺得Sprite顯示是一項(xiàng)非常重要的工作,足以保證它自己的組件。
import React from 'react'; export default function Sprite(props) { return ( <div className={`circle ${props.isSearched ? 'highlight' : ""}`} key={props.name} onClick={() => props.setSpecificAndPokemon(true, props.fullName)} > <img src={`${process.env.PUBLIC_URL}/regular/${props.name}.png`} alt={props.fullName} title={props.fullName} /> </div> ); }
在完整的版本中,你可以通過下拉菜單選擇要搜索的pokemon,但是我也希望能夠點(diǎn)擊精靈來搜索更多的pokemon。我們保留了alt文本的全名,title(如果你忘記了pokemon的名字,但是知道它是什么樣子的話,你可以把鼠標(biāo)懸停在上面),最重要的是,當(dāng)我們改變搜索條件時,我們使用pokemon的正確名稱。circle類和highlight類為我們提供了我在它們周圍放置的圓圈的外觀,以及pokemon是否是當(dāng)前正在搜索的那個。
circle { background-color: rgba(white, 0.3); border-radius: 50%; margin: 5px; cursor: pointer; } .highlight { background-color: rgba($link-color, 1); }
小額回報(bào)vs膨脹
我開始做一件事,我不敢肯定這件事是否好?我希望在我的呈現(xiàn)中有小的返回語句。
return ( <div id="app"> {this.state.specific ? lookSpecific : all} {searchAll} <div id="listing-container"> {this.state.general[89] ? listings : "Loading..."} </div> </div>
那很好。但是,它前面有這樣一條:
const { general, specific, searchPokemon } = this.state; let listings = this.listings(specific, searchPokemon) || 0; const all = <header>Searching last 30 results of 3 subreddits...</header>; const lookSpecific = <header>Searching last 90 results for trades containing {searchPokemon}...</header>; let cantFind = listings.length ? "" : "Couldn't find any trades!" const lookups = pokemonArray.map((pokemon, i) => { return ( <option key={pokemon + ` option`} value={pokemon} > {`${pokemon} #${i + 1}`} </option> ); }); const searchAll = <select onChange={e => this.setSpecificAndPokemon(true, e.target.value)} > <option key='none' value={null} onClick={() => this.setSpecificAndPokemon(false, null)} > None </option> {lookups} </select>
另一種方法是只在return語句中定義它,但是你會得到這樣的結(jié)果:在我看來這很難理解。
const { general, specific, searchPokemon } = this.state; let listings = this.listings(specific, searchPokemon) || 0; return ( <div id="app"> {this.state.specific ? <header>Searching last 90 results for trades containing {searchPokemon}...</header> : <header>Searching last 30 results of 3 subreddits...</header>} <select onChange={e => this.setSpecificAndPokemon(true, e.target.value)} > <option key='none' value={null} onClick={() => this.setSpecificAndPokemon(false, null)} > None </option> {pokemonArray.map((pokemon, i) => { return ( <option key={pokemon + ` option`} value={pokemon} > {`${pokemon} #${i + 1}`} </option> ) })} </select> <div id="listing-container"> {this.state.general[89] ? this.listings(specific, searchPokemon) || 0 : "Loading..."} </div> </div > ); }
這樣把它們分開是不對的,還是render語句應(yīng)該按照其中的內(nèi)容的順序來讀?對if語句使用立即返回函數(shù)非常難看,但使用真正長的三元運(yùn)算符也是難看的。
{(() => { if (ugly) { return <div> Man this is {`ugly`}.. </div> } else { return <div> But it's more informative? </div> } })()}
最后的想法
我覺得我已經(jīng)做了三次同一個項(xiàng)目的變化,但每次我都學(xué)到了一些東西。至少對我來說,想出我力所能及的好主意是困難的。我對一些游戲有一些想法要感謝朋友,但是我不太愿意為了游戲的目的而加入React,盡管我認(rèn)為這會對我的React技能有很大的幫助。我想這個想法有點(diǎn)太大了,所以我需要找到一個小游戲的想法。或者停止做React,為特定的體驗(yàn)制作Wordpress主題,但那并不是那么有趣。也許,只是也許,下次我會做一些與口袋妖怪無關(guān)的事。