关于Github Report 👨‍🚀

前言🛸

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 来使其有一个动画的效果），同时用时间戳实现了一个节流（单位时间内只执行一次某个方法），以防止用户频繁滚动✍：

Copy
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，这个函数返回一个数组，数组第一个元素是变量，第二个元素是一个方法，用于改变变量，例如：

Copy
// 声明一个叫 “count” 的 state 变量
const [count, setCount] = useState(0);

useEffect

useEffet 这个钩子函数可以说是替换了 componentDidMount, componentDidUpdate, componentWillUnmount 这三个生命周期，在组件第一次渲染的时候也会执行 useEffect ()，具体✍：

Copy
useEffect(
//等价于 componentDidMount
() => {

// return等价于 componentWillUnmount
return () => {

};
},
// 依赖列表，当变更时候，执行useEffent()，等价于 componentDidUpdate
[]
);

useContext

useContext () 可以使用在组件之间需要共享状态的情况下，不必显式地通过组件树的逐层传递 props

Copy
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 (

<ThemedButton />

);
}
// 孙级或更多级
function ThemedButton() {
const theme = useContext(ThemeContext);
return (

I am styled by theme context!

);
}

useRef

useRef 返回一个可变的 ref 对象，其 .current 属性被初始化为传入的参数（initialValue）。

返回的 ref 对象在组件的整个生命周期内持续存在，类似于一个 class 的实例属性，其可以很方便地保存任何可变值。

Copy
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 (
<>

Focus the input

// ...
</>
);
}

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 欢迎交流🙌

如果这个东西能帮到你学到点什么就是我的荣幸🔮