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