一直在研究如何解决我 React 后台右上角功能菜单该如何设计,这个东西涉及到跨组件操作,最终实现是在“列表页”显示“新增”,在“编辑页”显示“添加草稿”这样的菜单项。
想要实现这个操作,我总不可能封装一个组件,每切换一个页面就重新渲染一个上去吧!这个菜单目前是放在了 Header 里面,和下面的路由组件基本上是同等关系。
<Aside> 侧边栏
<Header> 页面头部
<Route> 渲染页面内容
一开始想过使用 Redux 实现,感觉有点小题大做。而 @Innei 之前告诉过我 React 有个叫做 Context
的东西,我看了半天,也试着写了进去,都没效果,真是头疼!
正当此时,我想起自己之前封装的 Fetcher
组件 - 基于 Fetch 封装的一个破玩意儿。它有一个“额外附加”的功能,可以让网页登录完成后的所有请求都带上指定的 Header。那就说明任何页面「import」之后,其实都是指向同一个组件的。鉴于这个特点,我就搞了一个专门堆数据的“存储组件”,并在需要它的页面上直接 map
遍历... 虽然 DOM 的刷新貌似有延迟,但是在功能上貌似是完全没问题!最起码可以点击操作!
import {data as theData} from '../utils/data';
...
theData.side_menu.map((item, key) => {})
操作菜单项的内容是没问题了,但是我之前的“登出”菜单项还是不行,点完之后报错。因为没有拿到 React-Router 的 History 对象,无法「push」跳转回登录界面。翻了半天文档,只发现 这个 名为 useHistory
的 Hooks API 貌似可行,但是我写的还是 HOC,并非 FC,无法使用 Hooks,那该怎么搞啊!
最终决定,直接更换 FC 式写法!因为这个 Header 组件里面没有太多涉及到生命周期的东西,于是就直接研究起了 FC 了!
import React, {useState} from "react";
import {data as theData} from '../utils/data';
import {Link, useHistory} from 'react-router-dom';
function Header(props) {
const [menu, setMenu] = useState(false);
// 切换菜单
const toggle = () => setMenu(!menu);
// 注销
const history = useHistory();
const logout = () => {
sessionStorage.removeItem("paul-token");
history.push("/");
}
return (
<header>
...
</header>
);
}
写完测试了一下,一切功能基本正常。可让我没想到的是,其实 React-Router 也是有 HOC 写法的,那个东西叫做 withRouter
!@Innei 一眼就看到了,而我翻了半天压根就没留意到这个东西!他说 HOC 写法其实就是套娃,确实有这种感觉,多了层东西就更臃肿了。
class ShowTheLocation extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
render() {
const { match, location, history } = this.props;
return <div>You are now at {location.pathname}</div>;
}
}
const ShowTheLocationWithRouter = withRouter(ShowTheLocation);
除了讨论技术,我还和 @Innei 讨论了有关目前就业的问题。他希望我跑跑上海北京这样的城市,可我却始终保守,担心在那边生活的严峻。毕竟很少出过远门,对当地的生活物价等等完全没有认识。再一个就是我对自己的技术仍然没有特别的自信,我不知道去那里会不会被 HR 吊打,压低底薪什么的!虽然都说年轻人就是得多闯闯,但我始终拿不出信心。可回想起之前在金山的苦逼实习经历,瞬间觉得我当时的举措是非常正确的...
欢迎你去看看他的想法:活在危机中