待读文章
route
react-guide.github.io/react-route…
- path 可以为绝对路径,但onEnter,onLeave 还是会按照 嵌套关系来执行
- 路由匹配 到最后一个
<Route path="/comments" ... /> 无效
<Redirect from="/comments" ... />
history react中的路径访问方式. 分为
- hashHistory ==>#/
- browserHistory ==> try_files $uri /index.html
IndexLink IndexRoute
//当精确匹配到 / 时下面的activeClassName 才会生效
<IndexLink to="/" activeClassName="active">
Home
</IndexLink>
在上面的代码中,根路由只会在精确匹配时才具有activeClassName属性。如果不想使用IndexLink组件,也可以使用Link组件中的onlyActiveOnIndex属性达到同样的效果。
<Link to="/" activeClassName="active" onlyActiveOnIndex={true}>
Home
</Link>
实际上,IndexLink组件就是对Link组件的onlyActiveOnIndex属性封装后的高阶组件。
动态路由
动态加载路由组件
//父组件
renderDetail(mode,pageType){
let dynamicDetail = require(`../components/content/${pageType}/index`)
return dynamicDetail
}
render(){
//const { pageType } = this.props; 这里的pageType是判断加载哪个子组件的条件
//我们先假设一个
pageType = firstComponent; //存在firstComponent这么一个文件夹里面有一个index.js组件
let DynamicDetail = this.renderDetail(pageType); //动态拿到这个组件
return(
<div className="detailWried">
<DynamicDetail />
</div>
)
}
//子组件
import React from 'react'
export default class firstComponent extends React.Component{
render(){
return(
<div>
NavMenu
</div>
)
}
}
module.exports = firstComponent;
按需(路由)加载
使用高阶组件来包装下, 在高阶组件内部去加载需要的组件, 中配置的都是高阶组件, 只有需要渲染(使用)的时候才加载组件 来源 create-react-app
import React from 'react';
export default function (getComponent) {
return class AsyncComponent extends React.Component { //高阶组件
static Component = null;
state = { Component: AsyncComponent.Component };
componentWillMount() {
if (!this.state.Component) {
getComponent().then(({default: Component}) => {
AsyncComponent.Component = Component
this.setState({ Component })
})
}
}
render() {
const { Component } = this.state
if (Component) {
return <Component {...this.props} />
}
return null
}
}
}
function load(component) {
return import(`$pages/${component}`)//$pages在webpack里面配置过是“./src/pages”的别名
}
//
// const Home = AsyncComponent(() => import(/* webpackChunkName: "Home" */ './Home/index.jsx'));]
import asyncComponent from './asyncComponent'
const Login = asyncComponent(() => load('login/login'))
const LayoutPage = asyncComponent(() => load('layout/layout'))
const NoticeDeatil = asyncComponent(() => load('noticeDetail/noticeDetail'))
export const appRouterMap = [
{path:"/login",name:"Login",component:Login,auth:false},
{path:"/web",name:"LayoutPage",component:LayoutPage,auth:false},
{path:"/notice/:id",name:"NoticeDeatil",component:NoticeDeatil,auth:false},
]
使用react-loadable实现
import Loadable from 'react-loadable';
const LoadableBar = Loadable({
loader: () => import('./components/Bar'),
loading() {
return <div>Loading...</div>
}
});
class MyComponent extends React.Component {
render() {
return <LoadableBar/>;
}
}
react-loadable-visibility [todo]
外部使用
// your main file that renders a Router
import { Router, browserHistory } from 'react-router'
import routes from './app/routes'
render(<Router history={browserHistory} routes={routes}/>, el)
// somewhere like a redux/flux action file:
import { browserHistory } from 'react-router'
browserHistory.push('/some/path')
组件
具名非具名组件 (vue slot)
函数式组件 : React.FC
T是prop 的类型
interface CustomizedFormProps {
onChange: (fields: FieldData[]) => void;
fields: FieldData[];
}
const CustomizedForm: React.FC<CustomizedFormProps> = ({ onChange, fields }) => {..}
hook
useEffect
useEffect两个注意点
-
React首次渲染和之后的每次渲染都会调用一遍useEffect函数,而之前我们要用两个生命周期函数分别表示首次渲染(componentDidMonut)和更新导致的重新渲染(componentDidUpdate)。
-
useEffect中定义的函数的执行不会阻碍浏览器更新视图,也就是说这些函数时异步执行的,而componentDidMonut和componentDidUpdate中的代码都是同步执行的。个人认为这个有好处也有坏处吧,比如我们要根据页面的大小,然后绘制当前弹出窗口的大小,如果时异步的就不好操作了。
-
useEffect的第二个参数可选,如果用上的话,这个参数必须是一个数组。useEffect在每次被调用的时候,都会“记住”这个数组参数,当下一次被调用的时候,会逐个比较数组中的元素,看是否和上一次调用的数组元素一模一样,如果一模一样,第一个参数(那个函数参数)也就不用被调用了,如果不一样,就调用那个第一个参数。 使用useEffect,表示告诉react,每次render(这里没写错,是每次render,包括第一次render和之后的每次update)之后需要做一些事情,什么事情呢?就是你写在useEffect里的代码。
结构:
useEffect(()=>{ // part A return part B; }); 和react 类相比较,也就是放在componentDidMount,componentDidUpdate里的代码,以及调用完setState之后需要做的事( 也就是采用此方式:this.setState({}, ()=>{ // 更新完此state值之后需要做的事 }))统统移到useEffect里。
怎么用?
- 单个useEffect使用
不管是react初次画好组件,还是之后的更新完组件,都会去执行useEffect的part A。如果你还返回了part B,那么react在卸载组件之前,以及每次执行part A去更新组件前,都会执行part B。当然你也可以不返回任何东西。
实际上,我们可以把useEffect看成componentDidMount, componentDidUpdate, componentWillUnMount的合体。Part A是写在componentDidMount和componentDidUpdate的代码,part B是写在componentWillUnMount的代码。
有人可能会说,我只想在componentDidMount和componentWillUnMount时执行代码。那么给useEffect加第二个参数,一个空数组。
useEffect(()=>{
// part A
return part B;
}, []);
第二个参数表示useEffect里面的part A和part B不依赖任何props, state, 因此不需要再次render,也就是这个useEffect只在componentDidMount和componentWillUnMount时执行代码。而part A, part B里涉及到的props和state始终是初始值,不会被更新。
如果第二个参数传[ list ],表示useEffect会在list发生改变时执行。也就是在
componentDidMount,componentDidUpdate( 检测到list更新之后)和componentWillUnMount时执行。
求证 React useEffect的陷阱 还是没懂!
function Zhihu() {
const [count, setCount] = useState(0)
//每次修改count时都会执行---组件重新渲染
//每次渲染的count 会变化
console.log('line 8', count, arguments)
useEffect(() => {
// 让resize事件触发handleResize
// 第一次会运行到这里,以后count 更新不会执行
console.log('line 11')
window.addEventListener('resize', handleResize)//只执行一次
return () => window.removeEventListener('resize', handleResize)
}, [])
const handleResize = () => {
// 把count输出
// 正常的闭包的话 , count 应该会变化, 但在这里不会变
console.log(`count is ${count}`)
}
return (
<div className="App">
<button onClick={() => setCount(count + 1)}>+</button>
<h1>{count}</h1>
</div>
)
}
dva
Route Components
相当于views/xxx.vue 就是路由中指定的组件,也叫页面
在组件设计方法中,我们提到过 Container Components,在 dva 中我们通常将其约束为 Route Components,因为在 dva 中我们通常以页面维度来设计 Container Components。
所以在 dva 中,通常需要 connect Model的组件都是 Route Components,组织在/routes/目录下,而/components/目录下则是纯组件(Presentational Components)。
dva-loading
//某个 [namespace]/[effects]
@connect(({ profile, loading }) => ({
profile,
loading: loading.effects['afterSaleList/afterSaleDetail'],
}))
监听单个effect
let isLoading = loading.effects['role/addRole'] //监听role下的addRole的异步请求
监听某个模块下的所有异步请求(只要有一个异步在do,isLoading)
let isLoading = loading.models.role,
全局监听所有异步请求
let isAllLoading = loading.global()