发布于:2021-02-19 00:02:20
0
243
0
从字面上看,自启动React以来,我所有的项目都是基于Pokemon或使用Pokemon艺术。她可能喜欢神奇宝贝吗?
通过编码我发现了一件奇怪的事情,那就是对数据进行排序很有趣?碰巧pokemon包含了许多有趣的数据小道消息,可以进行排序,并与其他内容进行匹配。所以,我再一次使用了一个API和一些pokemon,但是这次我们使用的是Reddit的API。
目标
从各个子Reddits获取数据
了解Reddit的api术语是什么
显示pokemon在标题和帖子中提到的内容
通过pokemon的交易进行搜索
我们都得到了吗?让我们看看发生了什么。
Reddit?
Reddit是互联网上的一个地方,由用户运行的subreddit组成。每样东西都有一个子项,事实上,可能每样东西都有不同的规则。对于这个项目,我想subreddits是专门用于交易的口袋妖怪,是经常更新,并使用类似的预修复。对于我选择的三个子项,它们在大多数查找中都使用LF(寻找)和FT(交易)。现在我们继续讨论如何使用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吗?它包含FT吗?如果有那么好的话。我们也无法查询和获取所有帖子,但如果有不符合格式的问题或mod更新,我们希望将其剔除。
`limit=30&restrict_sr=1`
有一个更严格的限制是100个,但我真的不希望人们通过300个条目,所以我们只会拉30个subreddit,共90个上市。限制的好处是,这都是一个api调用!下一部分,我们将搜索限制到我们定义的特定子项。为什么?我不知道。如果您不这样做,它会在所有子项中显示出来,这是我们真正不需要的。
`&sort=new`
如果你熟悉reddit,这个很简单。Reddit有各种模式可以按时间的顶端排序,按当前时间的热点排序,然后按最新的排序,等等。我们想要最新的交易,所以我们想要的不是相关性,而是最新的。
这些数据是什么?
很多。不幸的是,这还不够。我们可以遍历数据,进入被请求的30个孩子并获得大量数据!我们可以获取帖子标题,正文,风格,mod操作和...
不是日期?
创建字段的日期是发出请求的日期。正如我刚刚要求的那样,所以这是创建日期或utc。根据我的研究,没有为api提供可用的时间戳记。这给我的计划带来了麻烦。
原计划
我打算使用查询来查找pokemon相关的条目!因此,我们不使用常规查询,而是使用以下内容:
axios.get(`https://www.reddit.com/r/pokemontrades/search.json?q=Vulpix&limit=30&restrict_sr=1&sort=new`)
这确实有效。它将收集所有能找到的关于vulpix的帖子,最多30篇。不过,有些已经有几个月大了。虽然我有过简单地提供数据的实践,但作为一种更静态的资源,我希望它至少有点有用。当然,我可以搜索特定的pokemon,但是没有一个截止日期的方法,它只是白噪音,使它看起来更强大,然后有用。
新计划
缓存数据!我们的内容一旦是动态的,就不会像本地浏览器中的缓存那样,而是接受我们最初的调用并使用这些数据。因此,与其找一些关于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 ""; } });
关键是要使用一个唯一的标识符,这是原来的标题本身不是,因为在测试期间有人双重张贴,它真的搞砸了我的渲染。吸取的教训。searchPokemon是一个状态变量,它保存了我们当前正在搜索的pokemon,因此我们可以向下传递它并突出显示我们正在搜索的精灵。如果我们正在搜索一个特定的口袋妖怪或者没有,我们也会传递设置这个状态和布尔值的能力。
我最初让Entry组件来确定提到了哪个pokemon,但是就像React一样,您通常会找到一个理由来提升处理级别。上面提到的getpkmn只是通过pokemonArray(一个包含所有pokemon的数组,说真的,它很长)搜索标题和自我文本(body),看看pokemon是否出现在它的数据中。Search返回数据所在位置的数字,如果数据不在其中则返回-1,因此我们只需查看该数字是否大于-1即可推送到pokmemon提到的数组。由于大部分提到都是在身体里进行的,所以我决定先这样做,如果身体没有返回特定的口袋妖怪,它会在标题中搜索口袋妖怪,这样我们就不会加倍并掩盖我们的基础。
{this.state.general[89] ? listings : "Loading..."}
作为一个简短的说明,因为我们知道我们只搜索了90个条目,所以我们可以用它来确定我们是否完成了加载我们所做的三个调用。我喜欢这个api。一张纸条一张纸条,我其实不写此.state.value对于所有的事情,我只是在文章代码中有它,这样你就可以看到发生了什么。我应该做一个更复杂的加载动画,但它似乎太琐碎相比,它实际上需要多长时间加载。
条目组件
因为我们把pokemon的搜索从我们的条目中删除了(或者更确切地说,我在写这篇文章的时候忘了把它删除,谢谢您查看代码!)是相当稀疏的。最重要的一点是,我们的图像名称摆脱了特殊的字符和斩首他们,所以我们必须做一点正则表达式的魔力,使之工作。一点额外的魔力,将自我文本中的内容变回一个
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”
让我们花点时间来确认我所做的事情,因为如果我不这样做,React会对我大喊大叫。如果我在目标空白处打开,React会告诉我,在没有rel=“noopener noreferrer”的情况下这样做会有安全风险。让我用谷歌搜索一下,也许我们都会学到一些新东西。
我们链接到的页面通过开窗器“对象”。因此,可以在看起来合法的链接上插入javascript来重定向到一个不好的站点。这篇文章中最有趣的部分是,谷歌只是接受了这一点,认为这是“当前网页浏览器设计的固有特点,任何一个网站都无法有效缓解”。
精灵组件
比条目更小的是Sprite组件。只需将它插入到条目中,而不是它自己的组件是可能的,但我觉得Sprite显示是一项非常重要的工作,足以保证它自己的组件。
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,但是我也希望能够点击精灵来搜索更多的pokemon。我们保留了alt文本的全名,title(如果你忘记了pokemon的名字,但是知道它是什么样子的话,你可以把鼠标悬停在上面),最重要的是,当我们改变搜索条件时,我们使用pokemon的正确名称。circle类和highlight类为我们提供了我在它们周围放置的圆圈的外观,以及pokemon是否是当前正在搜索的那个。
circle { background-color: rgba(white, 0.3); border-radius: 50%; margin: 5px; cursor: pointer; } .highlight { background-color: rgba($link-color, 1); }
小额回报vs膨胀
我开始做一件事,我不敢肯定这件事是否好?我希望在我的呈现中有小的返回语句。
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语句中定义它,但是你会得到这样的结果:在我看来这很难理解。
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语句应该按照其中的内容的顺序来读?对if语句使用立即返回函数非常难看,但使用真正长的三元运算符也是难看的。
{(() => { if (ugly) { return <div> Man this is {`ugly`}.. </div> } else { return <div> But it's more informative? </div> } })()}
最后的想法
我觉得我已经做了三次同一个项目的变化,但每次我都学到了一些东西。至少对我来说,想出我力所能及的好主意是困难的。我对一些游戏有一些想法要感谢朋友,但是我不太愿意为了游戏的目的而加入React,尽管我认为这会对我的React技能有很大的帮助。我想这个想法有点太大了,所以我需要找到一个小游戏的想法。或者停止做React,为特定的体验制作Wordpress主题,但那并不是那么有趣。也许,只是也许,下次我会做一些与口袋妖怪无关的事。
作者介绍