摘要:設(shè)計(jì)的種模式本文翻譯自。剩下的肯定都是模式。真實(shí)的事實(shí)的特異性是網(wǎng)絡(luò)開(kāi)發(fā)人員死亡的第一原因。這種設(shè)計(jì)僅僅適用于登陸操作就在主頁(yè)面內(nèi)執(zhí)行,而不是多帶帶彈出一個(gè)模態(tài)窗口。這可以正常的工作,但確不是最好的方式。
設(shè)計(jì)React的10種模式
本文翻譯自10 React mini-patterns。這篇文章由mrcode翻譯, 如果哪里翻譯的不恰當(dāng)或有錯(cuò)誤的地方,歡迎指出。 同時(shí)也希望大家關(guān)注我的博客。 關(guān)注我的賬號(hào)。
在過(guò)去的幾年里,我已經(jīng)做了許多看起來(lái)挺不錯(cuò)的React項(xiàng)目。
在這個(gè)神奇的旅程中,一些模式出現(xiàn)過(guò)很多次,我發(fā)現(xiàn)我一次又一次地重復(fù)著這些模式。
什么是模式?
這些模式是我想在學(xué)習(xí)React第一天就知道的事情。
所以如果今天是你第一天學(xué)習(xí)React,你是如此的幸運(yùn)。
或者你并不幸運(yùn)。只有一種方法可以決定你是否是幸運(yùn)的...
這是一個(gè)長(zhǎng)長(zhǎng)的列表,所以你可以跳過(guò)無(wú)聊的一些模式, 比如:3,6,8,10。
1. Sending data down and up我建議大家新學(xué)習(xí)React的一件事是傳遞信息的模式(信息可以是對(duì)象,字符串等)和傳遞方法下來(lái)允許子組件傳遞信息給父組件。
就像把一包芯片和一個(gè)對(duì)講機(jī)送到地下被困的礦工一樣。
圖片怎么樣?
下面的事情是這種模式的最簡(jiǎn)單的形式。
父組件在左邊,子組件在右邊。
你可以認(rèn)為連接這些組件的兩個(gè)props允許信息在兩者之間的任一方向上流動(dòng)。
被稱(chēng)為items將被傳遞給子組件, deleteItem將提供給子組件一種方案來(lái)發(fā)送信息給父組件。
這不是一個(gè)真正的模式。剩下的肯定都是模式。我承諾。
2. Fixing HTML’s inputsReact和web組件的一個(gè)偉大的事情是,如果在html中的東西不能按你想要的方式工作,你可以解決它。
如果你考慮允許用戶(hù)輸入的不同元素,你很快就會(huì)看到這些元素的命名是荒謬的,幾乎是魯莽的。
如果我建立一個(gè)將有很多用戶(hù)輸入的網(wǎng)站,我做的第一件事之一是解決這個(gè)問(wèn)題。
還有更多的改進(jìn):
輸入應(yīng)該通過(guò)onChange方法返回一個(gè)值,而不是一個(gè)JavaScript事件實(shí)例,對(duì)不?
你可以進(jìn)一步確保在onChange返回的數(shù)據(jù)類(lèi)型和傳遞的數(shù)據(jù)類(lèi)型相匹配。如果typeof props.value是number,然后將e.target.value回到一個(gè)數(shù)字,然后再次發(fā)出數(shù)據(jù)。
一組單選按鈕在功能上與一樣
它是搞砸了,以一種完全不同的方式來(lái)對(duì)待它們,唯一的區(qū)別是UI。
也許你的應(yīng)用程序有一個(gè)單一的
關(guān)鍵是不要像我這樣做。
關(guān)鍵是要使它們成為你自己的 - 你不需要繼續(xù)使用HTML的用戶(hù)輸入元素的坑爹性質(zhì)。
關(guān)于輸入...如果你關(guān)心你的用戶(hù),你將通過(guò)id / for組合將元素綁定到你的。
但是你不想為你定義的每個(gè)輸入想出一些聰明和獨(dú)特的id,誰(shuí)有時(shí)間呢?我不知道你,但我有山羊的視頻觀看。
(提示:如果您的航班上有一個(gè)尖叫的孩子,閉上眼睛,假裝您在YouTube上觀看的山羊聽(tīng)起來(lái)像人類(lèi)的視頻,煩人的聲音就會(huì)變得很熱鬧。)
您可以為每個(gè)輸入/標(biāo)簽對(duì)生成隨機(jī)ID,但是客戶(hù)端呈現(xiàn)的HTML將與您呈現(xiàn)的服務(wù)器呈現(xiàn)的HTML不匹配。這并不是一個(gè)好的解決方案
所以,你可以創(chuàng)建一個(gè)小的模塊,給出一個(gè)遞增的ID,并在輸入組件中使用它,像這樣:
class Input extends React.Component { constructor(props) { super(props); this.id = getNextId(); this.onChange = this.onChange.bind(this); } onChange(e) { this.props.onChange(e.target.value); } render() { return ( ); } }
如果getNextId()每次只是增加一個(gè)數(shù)字,然后在服務(wù)器上渲染時(shí),這個(gè)數(shù)字會(huì)繼續(xù)上升和起來(lái),最終達(dá)到無(wú)窮大。因此,您需要在每次呈現(xiàn)應(yīng)用程序時(shí)重置該數(shù)字(對(duì)于每個(gè)網(wǎng)絡(luò)請(qǐng)求)。
你可以在你的應(yīng)用程序的入口點(diǎn),使用一個(gè)簡(jiǎn)單的resetId()或任何你認(rèn)為最好的名稱(chēng)。
考慮到所有這些,你的超級(jí)幻想模塊可能看起來(lái)像這樣:
let count = 1; export const resetId = () => { count = 1; } export const getNextId = () => { return `element-id-${count++}`; }4. Controlling CSS with props
當(dāng)你想在不同的實(shí)例(例如"primary"和"secondary"按鈕)應(yīng)用不同的CSS,你可以傳遞道具來(lái)控制要應(yīng)用的CSS。
這看起來(lái)超級(jí)簡(jiǎn)單的表面,但讓我向你保證有很多錯(cuò)誤的方法來(lái)做到這一點(diǎn)(我已經(jīng)嘗試過(guò)他們?。?。
有 - 我估計(jì) - 三種不同的方式,你可以控制應(yīng)用于組件的CSS。
使用標(biāo)志也許你的一些按鈕有圓角,但這不直接對(duì)應(yīng)于您定義的主題。
在這種情況下,你可以坐下你的設(shè)計(jì)師,并有一致性談話(huà),或創(chuàng)建一個(gè)布爾的道具,可能看起來(lái)像這樣:
就像HTML的二進(jìn)制屬性一樣,你不需要做round = {true}。
設(shè)置值在某些情況下,您可能希望直接傳遞CSS屬性的值(在組件中將其設(shè)置為內(nèi)聯(lián)樣式)。
假設(shè)您正在創(chuàng)建鏈接組件。你通過(guò)你的網(wǎng)站的設(shè)計(jì)和工作,有三個(gè)不同的主題,有時(shí)他們有一個(gè)下劃線(xiàn),有時(shí)他們不。
下面是我將如何設(shè)計(jì)該組件:
const Link = (props) => { let className = `link link--${props.theme}-theme`; if (!props.underline) className += " link--no-underline"; return {props.children}; }; Link.propTypes = { theme: PropTypes.oneOf([ "default", // primary color, no underline "blend", // inherit surrounding styles "primary-button", // primary color, solid block ]), underline: PropTypes.bool, href: PropTypes.string.isRequired, children: PropTypes.oneOfType([ PropTypes.element, PropTypes.array, PropTypes.string, ]).isRequired, }; Link.defaultProps = { theme: "default", underline: false, };
增加CSS...
.link--default-theme, .link--blend-theme:hover { color: #D84315; } .link--blend-theme { color: inherit; } .link--default-theme:hover, .link--blend-theme:hover { text-decoration: underline; } .link--primary-button-theme { display: inline-block; padding: 12px 25px; font-size: 18px; background: #D84315; color: white; } .link--no-underline { text-decoration: none; }
你可能已經(jīng)注意到鏈接 - 無(wú)下劃線(xiàn)的選擇器是沒(méi)必要存在的, 因?yàn)樗p重否定了。
故事時(shí)間:我曾經(jīng)認(rèn)為寫(xiě)CSS更少的CSS是目標(biāo),但它不是。我寧愿有一些雙重否定和多選擇器規(guī)則集,如果它的意思是樣式以一個(gè)很好的分層方式應(yīng)用的話(huà)。
我相信我以前說(shuō)過(guò),但縮放網(wǎng)站最困難的事情是CSS。 JavaScript很容易,但是隨意使用CSS使你很遭罪 - 一旦你開(kāi)始混亂,這是不容易中途修改來(lái)解決的。
真實(shí)的事實(shí):CSS的特異性是網(wǎng)絡(luò)開(kāi)發(fā)人員死亡的第一原因。如果你在一臺(tái)大型計(jì)算機(jī)上,請(qǐng)查看頂部導(dǎo)航欄中的小通知圖標(biāo)的CSS。
這個(gè)通知圖標(biāo)是由很多CSS樣式組合在一起的。很復(fù)雜。
二十三條規(guī)則。
這不包括繼承自十一個(gè)其他規(guī)則的樣式。行高多帶帶被覆蓋九次。
如果line-height是一只貓,它現(xiàn)在已經(jīng)死了。
這不能令人愉快地維護(hù)。
有了React,我們可以做得更好。我們可以仔細(xì)設(shè)計(jì)哪些類(lèi)應(yīng)用于我們的組件。我們可以刪除全局樣式和移動(dòng)它所有在我們的Button.scss。我們可以消除對(duì)文件的特異性和順序的所有依賴(lài)。
附注: 我夢(mèng)想著有一天游覽器對(duì)于樣式?jīng)]有自己的看法(意思就是所有游覽器都變得統(tǒng)一, 完全去IE化-。-)。
5. The switching component切換組件是呈現(xiàn)最多的組件之一。
這可能是一個(gè)顯示多個(gè)頁(yè)面之一的
我曾經(jīng)使用switch語(yǔ)句,進(jìn)一步到實(shí)際傳入我想要渲染的組件。然后從組件本身導(dǎo)出對(duì)組件的引用(命名為exports,然后作為組件上的屬性)。
真是一堆可怕的想法!
我現(xiàn)在的方法是使用一個(gè)對(duì)象傳遞props給Page組件。
import HomePage from "./HomePage.jsx"; import AboutPage from "./AboutPage.jsx"; import UserPage from "./UserPage.jsx"; import FourOhFourPage from "./FourOhFourPage.jsx"; const PAGES = { home: HomePage, about: AboutPage, user: UserPage, }; const Page = (props) => { const Handler = PAGES[props.page] || FourOhFourPage; return}; Page.propTypes = { page: PropTypes.oneOf(Object.keys(PAGES)).isRequired, };
PAGES對(duì)象的key可以在prop類(lèi)型中使用,以捕獲dev時(shí)間錯(cuò)誤。
然后,我們當(dāng)然會(huì)使用這樣
如果你用key替換home,about和user分別用/, /about和/user,你差不多就是個(gè)路由器了。
(未來(lái)的想法:再見(jiàn) react-router。)
6. Reaching into a component如果您正在尋找一個(gè)簡(jiǎn)單的方法來(lái)請(qǐng)求您的用戶(hù)輸入信息,那么你可以添加自動(dòng)對(duì)焦到輸入組件, 當(dāng)用戶(hù)一個(gè)頁(yè)面的時(shí)候。這種設(shè)計(jì)僅僅適用于登陸操作就在主頁(yè)面內(nèi)執(zhí)行, 而不是多帶帶彈出一個(gè)模態(tài)窗口。
你可以通過(guò)給輸入組件一個(gè)id,然后使用document.getElementById("user-name-input")。focus()來(lái)將用戶(hù)的焦點(diǎn)集中在輸入組件上。
這工作,但不是正確的方式。在你的應(yīng)用程序中依靠?jī)蓚€(gè)字符串匹配的事情越少越好。
這可以正常的工作, 但確不是最好的方式。 在你的代碼中依靠?jī)蓚€(gè)字符串匹配的事情越少越好。
幸運(yùn)的是,有一個(gè)非常容易的方法來(lái)做到這一點(diǎn)“正確”:
class Input extends Component { focus() { this.el.focus(); } render() { return ( { this.el = el; }} /> ); } }
真是酷炫屌炸天! 一個(gè)具有focus()方法的輸入組件,用于聚焦HTML元素。
在父組件中,我們可以獲得對(duì)Input組件的引用并調(diào)用其focus()方法。
class SignInModal extends Component { componentDidMount() { this.InputComponent.focus(); } render() { return ({ this.InputComponent = comp; }} />) } }
注意,當(dāng)在組件上使用ref時(shí),它是對(duì)組件(而不是底層元素)的引用,因此您可以訪(fǎng)問(wèn)其方法。
7. Almost-components假設(shè)您正在構(gòu)建一個(gè)組件,以便您可以搜索人員。在您輸入時(shí),您會(huì)看到一個(gè)可能匹配的名稱(chēng)和照片列表。這樣的東西。
(我正在尋找政治諷刺,因?yàn)槲蚁翊蠹乙粯樱瑢?duì)其他人對(duì)政治的看法極為感興趣。)
當(dāng)設(shè)計(jì)此組件時(shí),您可能會(huì)想到自己:該列表中的每個(gè)項(xiàng)目都是自己的SearchSuggestion組件?它真的只有幾行HTML和CSS,也許不是?但我曾經(jīng)被告知“如果有疑問(wèn),創(chuàng)造另一個(gè)組件”。
哦,我的,這是相當(dāng)稀爛的一個(gè)泡菜,不是嗎?
如果我是做這個(gè),我不會(huì)有一個(gè)多帶帶的組件。相反,只是一個(gè)renderSearchSuggestion方法返回每個(gè)條目的適當(dāng)?shù)腄OM。然后結(jié)果就是下面的代碼示例這樣:
const SearchSuggestions = (props) => { // renderSearchSuggestion() behaves as a pseduo SearchSuggestion component // keep it self contained and it should be easy to extract later if needed const renderSearchSuggestion = listItem => (
如果事情變得更復(fù)雜,或者您想在其他地方使用此組件,則應(yīng)該能夠?qū)⒋a復(fù)制/粘貼到新組件中。
不要過(guò)早組件化。組件不像茶匙;你可以有太多。(意思組件可以隨便復(fù)制, 但是茶匙不行)
8. Components for formatting text當(dāng)我第一次開(kāi)始使用React時(shí),我想到組件應(yīng)該是一個(gè)大東西,一種分組DOM的結(jié)構(gòu)塊的方法。但這樣組件表現(xiàn)的很一般。
這里是一個(gè)
const Price = (props) => { const price = props.children.toLocaleString("en", { style: props.showSymbol ? "currency" : undefined, currency: props.showSymbol ? "USD" : undefined, maximumFractionDigits: props.showDecimals ? 2 : 0, }); return {price} }; Price.propTypes = { className: React.PropTypes.string, children: React.PropTypes.number, showDecimals: React.PropTypes.bool, showSymbol: React.PropTypes.bool, }; Price.defaultProps = { children: 0, showDecimals: true, showSymbol: true, }; const Page = () => { const lambPrice = 1234.567; const jetPrice = 999999.99; const bootPrice = 34.567; return (); };One lamb is
{lambPrice} One jet is
{jetPrice} Those gumboots will set ya back
{bootPrice} bucks.
正如你可以看到,我使用強(qiáng)大的Intl字符串格式化庫(kù),這里有一個(gè)鏈接到他們的網(wǎng)站。
我應(yīng)該指出(在一些朋克之前),這不是一行代碼的保存。你可以很容易地使用函數(shù)來(lái)做到這一點(diǎn)。 (當(dāng)然,組件只是具有不同形狀括號(hào)的函數(shù)。)
這是更少的代碼,但對(duì)我的眼睛,不太好:
function numberToPrice(num, options = {}) { const showSymbol = options.showSymbol !== false; const showDecimals = options.showDecimals !== false; return num.toLocaleString("en", { style: showSymbol ? "currency" : undefined, currency: showSymbol ? "USD" : undefined, maximumFractionDigits: showDecimals ? 2 : 0, }); } const Page = () => { const lambPrice = 1234.567; const jetPrice = 999999.99; const bootPrice = 34.567; return (); };One lamb is {numberToPrice(lambPrice)}
One jet is {numberToPrice(jetPrice, { showDecimals: false })}
Those gumboots will set ya back {numberToPrice(bootPrice, { showDecimals: false, showSymbol: false })} bucks.
請(qǐng)注意,我不會(huì)檢查我在上述任何一個(gè)有效的數(shù)字。那是因?yàn)?…
9. The store is the component’s servant我可能寫(xiě)了這么幾千次:
if (props.user.signInStatus === SIGN_IN_STATUSES.SIGNED_IN)..
(我被告知,我夸張,像,一個(gè)gazillion時(shí)代。)
最近我決定,如果我做這樣的檢查,我做錯(cuò)了。我想只問(wèn)“是用戶(hù)登錄?”,而不是“用戶(hù)的登錄狀態(tài)等于登錄?”
的組件在他們的生命周期中所做的已經(jīng)足夠, 他們不應(yīng)該去擔(dān)心他們的父組件會(huì)傳一些什么參數(shù)。 比如說(shuō)Price不用管傳入的數(shù)據(jù)是否是數(shù)字。
你會(huì)看到,如果你的store中的數(shù)據(jù)被設(shè)計(jì)為與您的組件匹配,您的組件將更加簡(jiǎn)單。我之前說(shuō)過(guò),復(fù)雜性是bug隱藏的地方。組件中的復(fù)雜性越低,bug出現(xiàn)的幾率越低。
但是復(fù)雜這個(gè)問(wèn)題肯定存在。
我的建議是:
制定你的組件的一般結(jié)構(gòu)和他們需要的數(shù)據(jù)
設(shè)計(jì)您的store以支持這些要求
做任何你需要做的輸入數(shù)據(jù),使其適合store。
對(duì)于這最后一點(diǎn),我建議一個(gè)單一的模塊,所有的按傳入的信息重命名props,將字符串轉(zhuǎn)換為數(shù)字,將對(duì)象轉(zhuǎn)換為數(shù)組,將日期字符串轉(zhuǎn)換為日期對(duì)象。
如果你正在進(jìn)行一個(gè)react/redux, 你可以在一個(gè)動(dòng)作創(chuàng)建者中獲取搜索結(jié)果:
fetch(`/api/search?${queryParams}`) .then(response => response.json()) .then(normalizeSearchResultsApiData) // the do-it-all data massager .then(normalData => { // dispatch normalData to the store here });
你的組件將會(huì)感謝你的。
10. Importing components without relative paths不這樣做的話(huà)后患無(wú)窮啊!
import Button from "../../../../Button/Button.jsx"; import Icon from "../../../../Icon/Icon.jsx"; import Footer from "../../Footer/Footer.jsx";
或者你可以這樣做
import {Button, Icon, Footer} from "Components";
理論上你可以:
在導(dǎo)出每個(gè)組件的地方創(chuàng)建單個(gè)index.js
使用Webpack的resolve.alias將組件重定向到該索引文件
但是當(dāng)我寫(xiě)的代碼我來(lái)認(rèn)識(shí)到這是一個(gè)壞主意,有三個(gè)原因:當(dāng)我寫(xiě)代碼的時(shí)候, 我才認(rèn)識(shí)到上面的模式并不好,原因有三個(gè)。
在Webpack2 似乎改變了原有的API。
eslint將會(huì)檢測(cè)到錯(cuò)誤, 由于找不到你引用的組件(因?yàn)閞esolve.alias)。
如果你使用一個(gè)好的IDE,它會(huì)知道你的組件在哪里。你會(huì)得到關(guān)于不提供所需props的提示, 也無(wú)法通過(guò)Command+click 打開(kāi)文件這個(gè)功能。如果你這樣做,你的IDE將不再知道在哪里找到該組件,你會(huì)失去這些給力的功能。
Wrap up這就是全部, 我非常確定我將在今年看到這些模式的應(yīng)用。 或許你們今天就會(huì)使用它。 你也可以分享一些你覺(jué)得不錯(cuò)的模式。
喔, 我決定我不關(guān)心你是否點(diǎn)擊了綠色的心。
I WILL NOT BE DEFINED BY AN INTERNET METRIC.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/88146.html
摘要:詳情怎樣規(guī)避地獄作者先介紹什么是地獄,以及在開(kāi)發(fā)過(guò)程中怎樣去規(guī)避地獄,一時(shí)爽性能問(wèn)題火葬場(chǎng)。詳情其他亮點(diǎn)匯總開(kāi)發(fā)者大會(huì)已于北京時(shí)間月日凌晨在美國(guó)山景城正式啟幕。 【前端】 1. JavaScript 的新數(shù)據(jù)類(lèi)型:BigInt BigInt?是 JavaScript 中的一個(gè)新的數(shù)字基本(primitive)類(lèi)型,可以用任意精度表示整數(shù)。使用?BigInt?可以安全地存儲(chǔ)和操作大整數(shù),...
摘要:詳情怎樣規(guī)避地獄作者先介紹什么是地獄,以及在開(kāi)發(fā)過(guò)程中怎樣去規(guī)避地獄,一時(shí)爽性能問(wèn)題火葬場(chǎng)。詳情其他亮點(diǎn)匯總開(kāi)發(fā)者大會(huì)已于北京時(shí)間月日凌晨在美國(guó)山景城正式啟幕。 【前端】 1. JavaScript 的新數(shù)據(jù)類(lèi)型:BigInt BigInt?是 JavaScript 中的一個(gè)新的數(shù)字基本(primitive)類(lèi)型,可以用任意精度表示整數(shù)。使用?BigInt?可以安全地存儲(chǔ)和操作大整數(shù),...
摘要:詳情怎樣規(guī)避地獄作者先介紹什么是地獄,以及在開(kāi)發(fā)過(guò)程中怎樣去規(guī)避地獄,一時(shí)爽性能問(wèn)題火葬場(chǎng)。詳情其他亮點(diǎn)匯總開(kāi)發(fā)者大會(huì)已于北京時(shí)間月日凌晨在美國(guó)山景城正式啟幕。 【前端】 1. JavaScript 的新數(shù)據(jù)類(lèi)型:BigInt BigInt?是 JavaScript 中的一個(gè)新的數(shù)字基本(primitive)類(lèi)型,可以用任意精度表示整數(shù)。使用?BigInt?可以安全地存儲(chǔ)和操作大整數(shù),...
摘要:詳情怎樣規(guī)避地獄作者先介紹什么是地獄,以及在開(kāi)發(fā)過(guò)程中怎樣去規(guī)避地獄,一時(shí)爽性能問(wèn)題火葬場(chǎng)。詳情其他亮點(diǎn)匯總開(kāi)發(fā)者大會(huì)已于北京時(shí)間月日凌晨在美國(guó)山景城正式啟幕。 【前端】 1. JavaScript 的新數(shù)據(jù)類(lèi)型:BigInt BigInt?是 JavaScript 中的一個(gè)新的數(shù)字基本(primitive)類(lèi)型,可以用任意精度表示整數(shù)。使用?BigInt?可以安全地存儲(chǔ)和操作大整數(shù),...
閱讀 2844·2021-11-24 09:39
閱讀 4150·2021-10-27 14:19
閱讀 2059·2021-08-12 13:25
閱讀 2347·2019-08-29 17:07
閱讀 1124·2019-08-29 13:44
閱讀 1076·2019-08-26 12:17
閱讀 474·2019-08-23 17:16
閱讀 2059·2019-08-23 16:46