likes
comments
collection
share

React高级指引(上)

作者站长头像
站长
· 阅读数 21

无障碍辅助功能

无障碍辅助功能是使得辅助技术正确解读网页的必要条件可以从以下几个方面考虑设计:语义化的HTML、无障碍的表单、控制焦点、鼠标和指针事件、语言、文档标题、色彩对比度等

代码分割

对应用进行代码分割能够“懒加载”当前用户所需要的内容,能够显著地提高应用性能。尽管并没有减少应用整体的代码体积,但避免加载用户永远不需要的代码,在初始加载的时候减少所需加载的代码量。

  1. import()
  2. React.lazy

有关React.lazy: React.lazy 和 Suspense 技术还不支持服务端渲染。如果想要在使用服务端渲染的应用中使用,可以使用 Loadable Components 这个库。 React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 default export 的 React 组件。然后应在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)fallback 属性接受任何在组件加载过程中你想展示的 React 元素。你可以将 Suspense 组件置于懒加载组件之上的任何位置。你甚至可以用一个 Suspense 组件包裹多个懒加载组件。

show you the code

import React , { Suspense } from 'react';

const PageTitle = React.lazy(()=>import('./components/pageTitle'))
const Left = <LeftIcon/>

function MyComp(){
  return(
    <Suspense fallback={<h1>Loading</h1>}>
      <PageTitle title="目标" leftItem={Left}/>
    </Suspense>
  )
}

错误边界

在子组件树的任何位置捕获 JavaScript 错误,记录这些错误,并显示一个备用 UI ,而不是使整个组件树崩溃Tips:

  • 只有class组件才能成为错误边界组件
  • 错误边界无法捕获以下场景中产生的错误:

    1. 事件处理,若想在事件处理器内部捕获错误,可使用普通的 JavaScript try / catch 语句
    2. 异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)
    3. 服务端渲染
    4. 它自身抛出来的错误(并非它的子组件)
  • 如果一个错误边界无法渲染错误信息,则错误会冒泡至最近的上层错误边界,这也类似于 JavaScript 中 catch {} 的工作机制。

show you the code

// 未添加错误边界

function App(){
return (
    <div className="page">
      <MyComp/>
      <h2>正常展示的内容</h2>
    </div>
  );
}

function MyComp(){
  return(
    <div>{ Math.random() > 0.2 ? new Error('自定义错误!!!') : '没有错误'}</div>
  )
}

此时子组件报错,导致整个页面crashReact高级指引(上)

// 添加错误边界后的代码

function App(){
return (
    <div className="page">
      <MyComp/>
      <h2>正常展示的内容</h2>
    </div>
  );
}
function MyComp(){
  return(
    <MyErrorBoundary>
      <div>{ Math.random() > 0.2 ? new Error('自定义错误!!!') : '没有错误'}</div>
    </MyErrorBoundary>
  )
}

class MyErrorBoundary extends React.Component{
  constructor(props:any){
    super(props)
    this.state = { hasError : false}
  }

  static getDerivedStateFromError(){
    return { hasError : true}
  }

  componentDidCatch(error,info){
    console.error(error,info);
  }

  render(){
    if(this.state.hasError){
      return(
        <h1>Oops,there's something wrong</h1>
      )
    }else{
      return this.props.children
    }
  }
  
}

此时子组件报错,整个页面未crashReact高级指引(上)

anyway,错误边界的粒度由你来决定,可以将其包装在最顶层的路由组件并为用户展示一个 “Something went wrong” 的错误信息,就像服务端框架经常处理崩溃一样。你也可以将单独的部件包装在错误边界以保护应用其他部分不崩溃。

Context

无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法,但如果你只是想避免层层传递一些属性,组件组合有时候是一个比 context 更好的解决方案:将组件自身作为属性传下去

动态Context的实例:

const myContext = createContext(null)

function MyComp(){
  const [theme,setTheme] = useState<string>('dark')
  const themes = {
    theme,
    onThemeChange:setTheme
  };
  return(
    <myContext.Provider value={themes}>
      <ThemeInput/>
    </myContext.Provider>
  )
}

function ThemeInput(){
  const themeStatus = useContext(myContext)
  const {theme, onThemeChange} = themeStatus
  return (
    <>
      <input value={theme} onChange={(val)=>onThemeChange(val.target.value)}/>
      <ThemeResult/>
    </>
  )
}

function ThemeResult(){
  const themeStatus = useContext(myContext)
  return(
    <span>the theme is {themeStatus.theme}</span>
  )
}

虽然这个例子直接写成非受控组件就完事,单纯是为了展示一下context的使用React高级指引(上)

高阶组件

高阶组件是参数为组件,返回值为新组件的函数。Tips:Refs 不会被传递

Refs转发

Ref 转发是一项将 ref 自动地通过组件传递到其一子组件的技巧

传递Refs到Dom组件Tips:第二个参数 ref 只在使用 React.forwardRef 定义组件时存在。常规函数和 class 组件不接收 ref 参数,且 props 中也不存在 ref。

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} {...props}>
    {props.children}
  </button>
));

function MyComp(){
  const ref = React.createRef();
  const handleButtonClick = useCallback(()=>{
    console.log('ref.current',ref.current);
  },[ref])
  return(
    <FancyButton ref={ref} onClick={handleButtonClick}>Click me!</FancyButton>
  )
}

Fragments

React 中的一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。可以使用一种新的,且更简短的语法来声明 Fragments:<></>,但它并不支持 key 或属性。key是唯一可以传递给 Fragment 的属性