组件懒加载
使用 React.lazy
和 React.Suspense
实现组件的懒加载
import React, { Suspense } from 'react';
const component = React.lazy(()=>import('./someComponent.js'))
const T = () => {
return (
<Suspense fallback={<div>loading...</div>}>
<component />
</Suspense>
)
}
Context 全局上下文
- 注意: 被注入context的组件,当context改变时,组件就会重新渲染,无论组件是否使用了context
- 注意: context中的value是通过
Object.is
比较新旧值 (所以当value是个对象时,初始化的时候需要传state,而不是直接在value中写个对象) - 使用context前的考虑: 那种真的会被全局使用到的属性, 如主题这种,才有必要通过context传递
使用方式:
- 创建context
const MyContext = React.createContext(defaultValue);
- 挂载context
<Mycontext.Provider value={/* someValue */}>
{/*
消费组件
*/}
</Mycontext.Provider>
- 在消费组件中使用
// 函数组件中使用useContext使用
import MyContext from './xx.js'
import { useContext } from 'react'
const ctx = useContext(MyContext) // 获取到了context中的value
// 在类组件中使用 Context.Consumer 或 contextType
// ------------- contextType
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/* 在组件挂载完成后,使用 MyContext 组件的值来执行一些有副作用的操作 */
}
render() {
let value = this.context;
/* 基于 MyContext 组件的值进行渲染 */
}
}
MyClass.contextType = MyContext;
// ------------ Context.Consumer
<MyContext.Consumer>
{value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>
Ref转发
通俗来说: 把一个组件中的ref转发给他的父组件。 有时候我们需要控制button的焦点,这个时候或许就能用到ref转发
- 注意: 第二个参数
ref
只在使用React.forwardRef
定义组件时存在。常规函数和 class 组件不接收ref
参数,且 props 中也不存在ref
。
const FancyButton = React.forwardRef((props, buttonRef) => (
<button ref={buttonRef} className="FancyButton">
{props.children}
</button>
));
// 你可以直接获取 button 的 ref:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
Fragments
类似vue中的template, 无意义的节点,不会渲染到dom树中 新语法: <></>
高阶组件
目前我还没用自己写过高阶组件。 高阶组件就是传入一个组件,返回一个新组件。高阶组件可以对组件进行一系列的处理
- 注意: 在高阶组件中,不要改变传入的参数组件
其余待我使用之后再补充
深入JSX
动态组件
在vue中,动态组件是用 <component is="xx">
在react中, 动态组件很简单
import A from './a.js'
import B from './b.js'
const C = (props) => {
const components = {
A,
B
}
const DynamicComponent = components[props.type]
return (
<DynamicComponent />
)
}
属性默认
react与vue相同,props未赋值表示true
// 两个等价
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />
插槽
习惯了这个称呼,但其实在react中没有插槽的说法 在vue中,插槽是这样用的
// A.vue
<template>
<div>
<div>
<span>这是一些文字</span>
<slot name="icon"></slot> // 具名插槽
</div>
<div>
<slot></slot> // 默认插槽
</div>
</div>
</template>
<script>
export default {
};
</script>
// B.vue
<template>
<div v-for="i in 10">
<A key="i">
<span slot="icon">图标</span>
<div>插入到默认插槽的</div>
</A>
</div>
</template>
<script>
import 'A' from './A.vue'
export default {
components: { A }
};
</script>
在react中,可以这样
const SlotComp = (props) => {
const { children } = props // children是一个数组
const Icon = children.xxxx // 伪代码,从props中取Icon
const Default = children.yyy
return (
<div>
<div>
<span>这是一些文字</span>
{Icon}
</div>
<div>
{Default}
</div>
</div>
)
}
import SlotComp from './x.js'
const M = () => {
return (
<>
<SlotComp>
<icon name='icon' />
<div>默认的一些内容xxx</div>
</SlotComp>
<SlotComp>
<icon name='icon' />
<div>默认的一些内容xxx</div>
</SlotComp>
</>
)
}
还可以使用 render Prop
, 比较复杂的情况,比如需要向slot传值时,就可以使用 renderProp
条件渲染的易错点
我犯过这种错, 现在知道原理了。 值得注意的是有一些 “falsy” 值,如数字 0
,仍然会被 React 渲染。例如,以下代码并不会像你预期那样工作,因为当 props.messages
是空数组时,0
仍然会被渲染:
// 如果length为0, 页面会渲染 0.
<div>
{props.messages.length && <MessageList messages={props.messages} />}
</div>
要解决这个问题,确保 &&
之前的表达式总是布尔值
<div>
{props.messages.length > 0 && <MessageList messages={props.messages} />}
</div>
性能优化
这里只说一个,虚拟长列表。 react-window 和 react-virtualized
react-transition-group
类似vue的transition, 有一说一,vue的transition确实好用,增强了用户体验(也针对开发) 在react中,这样来写
import { Button } from 'antd'
import React, { useState } from 'react'
import { CSSTransition } from 'react-transition-group'
import './index.less'
import styles from './index.module.less'
const Ide = () => {
const [box1, setBox1] = useState<boolean>(true)
return (
<>
<CSSTransition in={box1} classNames='box1' unmountOnExit timeout={1000} onEnter={()=>{console.log('enter')}} onEntered={()=>{console.log('entered')}} onEntering={()=>{console.log('entering')}} mountOnEnter>
<div className={styles.test}></div>
</CSSTransition>
<Button type='primary' onClick={() => setBox1(!box1)}>change</Button>
</>
)
}
export default Ide
.box1-enter {
opacity: 0;
transform: scale(0.5);
}
.box1-enter-active {
opacity: 1;
transition: all 1s;
transform: scale(1);
}
.box1-exit {
opacity: 1;
transform: scale(1);
}
.box1-exit-active {
transform: scale(0.5);
transition: all 1s;
opacity: 0;
}
关键参数介绍:
- in: 控制transition显隐
- unmountOnExit: 隐藏后是否卸载组件
- mountOnEnter: 默认子组件会立即跟随transition组件一起挂载到dom上,如果想在第一次渲染时
in={true}
的情况下懒加载组件,就可以设置mountOnEnter
。如果指定了mountOnEnter
, 那么即使隐藏了,组件也不会卸载,除非设置了unmountOnExit
- timeout指定过渡时间,毫秒为单位。可以为每个过程单独设置过渡时间: {appear: 300, enter:400, exit: 500}。跟css中transition的过渡时间对应
- 状态回调函数,onEnter之类的
- appear 好像在 CSSTransition中没有用