react note

216 阅读1分钟

待读文章

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里。

怎么用?

  1. 单个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 就是路由中指定的组件,也叫页面

image.png 在组件设计方法中,我们提到过 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()