React基础与实践 | 青训营笔记

76 阅读2分钟

React基础与实践 | 青训营笔记

React简介与特性
React特点
  • 声明式
  • 组件化
  • 跨平台编写

等待资源加载实践和大部分情况下浏览器单线程执行是影响web浏览器性能的主要原因

_ErrorBoundary

class ErrorBoundary extends React.Component {
    constructor(props) {
        super(props)
        this.state = { hasError: false }
    }
    static getDerivedStateFromError() {
        // 更新state 使下一次渲染能够实现降级UI
        return { hasError: true }
    }
    componentDidCatch(error, errorInfo) {
        logger.error(error, errorInfo)
    }
    render() {
        if (this.state,hasError) {
            return <Empty description='xxx' />
        }
        return this.props.children
    }
}
React 更新流程
  • Scheduler ( 调度器 )

    • 维护时间切片
    • 与浏览器任务调度
    • 优先级调度
  • Reconciler ( 协调器 )

    • 将 JSX 转化为 Fiber
    • Fiber 树对比 ( 双缓存 )
    • 确定本次更新的 Fiber
  • Renderer ( 渲染器 ):渲染器用于管理一棵 React 树, 使其根据底层平台进行不同的调用

React基础温故知新
用React开发web应用
  • 架构:打包配置 JSX -> babel -> JS , 加载优化和错误降级
  • 路由:React Router 向应用中快速的添加视图和数据流,保持页面与URL间的同步
  • UI:可复用 UI -> 组件 -> 页面,可复用逻辑抽离成 hook
  • 状态:多页面多组件共享信息 redux & context
Hook使用规则
  • 只能在最顶层使用 Hook
// 错误示例代码
if (xxx) {
    useEffect() {}
}
// 正确示例代码
useEffect() {
    if (xxx) 
}
  • 只能在React函数中调用Hook

    • 在React函数组件中 或 自定义 Hook中调用
    • 自定义Hook必须以use开头
    • Hook中的state是完全隔离的
父组件给子组件通信

案例1:父组件通过选择size大小传递给子组件表单 进行展示

// SizeWrapper
<div>
    {
        React.Children.map(children, (child) => {
            if (child && child.props) {
                return React.cloneElement(child, commonProps)
            }
            return child
        })
    }
</div>
// before
<div>
    <Input value='input' size={props.size} />
    <InputTag value={['input-tag']} size={props.size} />
</div>
// after
<SizeWrapper size={props.size}>
    <Input value='input' />
    <InputTag value={['input-tag']} />
</SizeWrapper>

案例2:父组件给子组件传递一个对象,实现form表单的改变和清空

const FormComponent = (props, ref) {
    const [fromInstance] = Form.useForm()
    // 给 ref 添加 change,clear 方法
    useImperativeHandle(ref, () => {
        change: () => formInstance.setFieldsValue(newValue),
        clear: () => formInstance.clearFields(['username', 'email'])
    })
    return ...
}
// 转发ref
const FormConponentWithRef = forwardRef(FormComponent);
const FromWrapper = () => {
    const formRef = useRef(null)
    return <div>
        <Button onClick={()=>formRef.current?.change()}>change</Button>
        <Button onClick={()=>formRef.current?.clear()}>clear</Button>
        <FromComponentWithRef ref={formRef} />
    </div>
}

案例3:组件间共享信息——context & reducer

// 定义 reducer
export const userReducer = (state, action) => {
    switch (action.type) {
        case 'SET':
            return action.user
        case 'UPDATE':
            return {...state, ...action.user}
        case 'REMOVE':
            return undefined
        default:
            return state
    }
}
​
// 创建公共状态容器 store
export default createStore(userReducer)
// 一、传递context
export const GlobalContext = createContext({})
​
export default () => {
    const [state, dispatch] = useReducer(userReducer, store)
    return
        <GlobalContext.Provider value={{ state, dispatch }} >
            <xxx />
        </GlobalContext.Provider>
}
​
function xxx() {
    const { state: user, dispatch } = useContext(GlobalContext)
    const login = (user) => dispatch?.({ type: 'SET', user })
}
// 二、传递Store
import store from './store'
import { Provider } from 'react-redux'
export default () => {
    <Provider store={store}>
        <xxx />
    </Provider>
}
function xxx(props) {
    const { login, logout, user } = props
    return xxx
}
export default connnect(
    (state: IUserInfo) => ({ user: state })
    (dispatch) => ({
        login: (user:IUserInfo) => dispatch({ type:'SET', user })
        logout: () => dispatch({ type: 'REMOVE' })
    })
)(xxx)