前言🛸#
GitHub 是透過 Git 進行版本控制的軟體源代碼托管服務平台,由 GitHub 公司(曾稱 Logical Awesome)的開發者 Chris Wanstrath、P. J. Hyett 和湯姆・普雷斯頓・沃納使用 Ruby on Rails 編寫而成。截止到 2020 年 1 月,GitHub 已經有超過 4000 萬註冊用戶和 1.9 億代碼庫(包括至少 2800 萬開源代碼庫),事實上已經成為了世界上最大的代碼存放網站和開源社區。
Github 作為世界上最大的開源社區,對我編程的學習可以說是舉足輕重的,曾用它抄別人代碼來度過作業的危機, 在之前使用 Puppeteer 嘗試爬取了 Github 的部分數據,於是腦子一抽, 靈光一閃,決定配合之前寫的後台,結合下自己想嘗試的 react 函數式組件去寫一個頁面來展示一個人 Github 的一些數據。
項目地址:Github Report
NES.css🚀#
NES 是 20 世紀 80 年代末、90 年代初進入中國,是 80 後最早接觸的遊戲機,俗稱紅白機,這是一台使用 8 位處理器的遊戲主機,而 NES.css 是一款 NES 風格(8 位機)的 CSS 框架,也是一款像素風的 CSS 元件庫,它沒有任何 JavaScript 依賴,只包含 CSS。
NES.css 提供的元件樣式很對我胃口,它還提供了一些很好玩的像素 icon。NES.css 在默認裡只有英文字體是像素風格的,如果是需要別的語言也是像素風格的話,需要自行去下載字體。
👀具體使用參考看官方文檔:NES.css
React-spring🌏#
在最一開始我就想做一個整頁滾動的效果,我每個頁面都是 100vh,隱藏掉滾動條後監聽鼠標滾動(移動端監聽 touch),滾動執行的方法是整個頁面上滑或則下滑 100vh(使用 margin-top,超出的部分隱藏,並且設置 transition 來使其有一個動畫的效果),同時用時間戳實現了一個節流(單位時間內只執行一次某個方法),以防止用戶頻繁滾動✍:
function throttle(event, time) {
let pre = 0;
return function (...args) {
if (Date.now() - pre > time) {
pre = Date.now();
event.apply(this, args);
}
}
}
效果是有的,但是又感覺有點普通了🤨,接著翻到 React-spring 文檔裡看到了 Parallax,Parallax 可以創建一個可以滾動的容器,然後使用 ParallaxLayer 包含內容,並且可以設置其偏移量以及速度,就是可以製造視差滾動(頁面上很多的元素在相互獨立地滾動著),覺得挺好看就立馬採用了😆。
在網上有看到過使用 background-attachment(背景圖像的位置是在視口內固定,還是隨著包含它的區塊滾動),以及 transform(通過設置 translateZ,滾動的上下距離也就不一樣)來實現,但是看 react-spring 中的 Parallax 是使用 js 實現的,通過監聽滾動,實時使用 translate 設定位置🤔
有時間得要好好看下,文檔在這👉:React-spring
React Hook📡#
既然是使用了 react 的函數式組件,那麼肯定就繞不開它的鉤子函數了。說幾個我常用的吧。
useState#
為函數式組件引入 state,這個函數返回一個數組,數組第一個元素是變量,第二個元素是一個方法,用於改變變量,例如:
// 聲明一個叫 “count” 的 state 變量
const [count, setCount] = useState(0);
useEffect#
useEffet 這個鉤子函數可以說是替換了 componentDidMount, componentDidUpdate, componentWillUnmount 這三個生命週期,在組件第一次渲染的時候也會執行 useEffect (),具體✍:
useEffect(
//等價於 componentDidMount
() => {
// return等價於 componentWillUnmount
return () => {
};
},
// 依賴列表,當變更時候,執行useEffent(),等價於 componentDidUpdate
[]
);
useContext#
useContext () 可以使用在組件之間需要共享狀態的情況下,不必顯式地通過組件樹的逐層傳遞 props
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = React.createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
// 子級
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
// 孫級或更多級
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}
useRef#
useRef 返回一個可變的 ref 對象,其 .current 屬性被初始化為傳入的參數(initialValue)。
返回的 ref 對象在組件的整個生命週期內持續存在,類似於一個 class 的實例屬性,其可以很方便地保存任何可變值。
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const intervalRef = useRef();
const onButtonClick = () => {
// `current` 指向已掛載到 DOM 上的文本輸入元素
inputEl.current.focus();
};
useEffect(
() => {
const id = setInterval(() => {
// ...
});
intervalRef.current = id;
return () => {
clearInterval(intervalRef.current);
};
});
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
// ...
</>
);
}
Warning 🔒#
- ✅只在最頂層使用 Hook(不要在循環、條件或嵌套函數中使用 Hook)
- ✅在 React 函數中調用 Hook
- ✅在自定義 Hook 中調用其他 Hook
以上是 React Hook 文檔中的規則,原因就是 React 內部並不是真正保存 state,它是通過調用順序來跟蹤 state。
也就是說 多個 useState 的調用是借由一個鏈表來維護的,通過索引來實現對多個 state 的識別。 如果在 if/else 中調用 Hook,當函數組件重新執行的時候可能會改變調用順序,會導致錯誤。
這個過程:
- 第一次渲染,根據 useState 順序,逐個聲明 state 並且將其放入全局 Array 中。每次聲明 state,都要將 cursor 增加 1。
- 每個事件都有對應游標的 state 值,任何 state 事件觸發,都会修改 state 數組中對應的 state 值,觸發再次渲染。cursor 被重置為 0。按照 useState 的聲明順序,依次拿出最新的 state 的值,視圖更新。
最後🔭#
感謝NES.css以及React-spring🙏
這是我個人的心血來潮的學習項目,有改善的地方或者 bug 歡迎交流🙌
如果這個東西能幫到你學到點什麼就是我的榮幸🔮