学习React Advanced Guides

9 篇文章 0 订阅
本文深入讲解React的关键概念,包括状态管理、事件处理、列表与keys的最佳实践,以及如何使用Context API、Error Boundaries、Refs和Portals等高级特性。探讨了组件间状态提升的策略,渲染属性的复用,以及React的和解算法。适合希望深化React理解的开发者阅读。
摘要由CSDN通过智能技术生成

基础概览

state 的使用

  • React可以将多个 setState()调用合并成一个调用来提高性能

  • 状态更新可能是异步的

  • 不能依靠 this.propsthis.state 计算下一个状态

  • setState的第二种形式

    this.setState((prevState, props) => {
        // 先前的状态 prevState
        // 此次更新被应用的 props
    })

     

事件处理

  • arrow functionsFunction.prototype.bind 两种为事件处理函数传递参数

    • arrow functions 使用这种语法的问题是每次该组件渲染时都会创建一个不同的回调函数

      • 如果该回调函数作为属性值传入低阶组件,这些组件可能会进行额外的重新渲染

列表 & keys

  • 如果列表项目的顺序可能会变化,我们不建议使用索引来用作键值,因为这样做会导致性能的负面影响,还可能引起组件状态问题。

状态提升

  • 使用 react 经常会遇到几个组件需要共用状态数据的情况。这种情况下,我们最好将这部分共享的状态提升至他们最近的父组件当中进行管理。

定义UI状态的最小表示

  • 找出 state

    1. 它是通过 props 从父级传来的吗?如果是,他可能不是 state。

    2. 它随着时间推移不变吗?如果是,它可能不是 state。

    3. 你能够根据组件中任何其他的 state 或 props 把它计算出来吗?如果是,它不是 state。

  • 确定 state 的位置

    1. 确定每一个需要这个 state 来渲染的组件

    2. 找到一个公共所有者组件

    3. 公共所有者拥有这个 state

进阶指南

Context

  • React组件通过props传递数据,是自顶向下的

  • context可以传递数据通过组件树,而不用向每个层级层层传递props

    • 好处: 避免层层传递props,底层才能拿到数据

    • 如果只想避免通过许多级别传递一些属性,那么组件组合通常比上下文更简单

    • 谨慎的使用context,它可能会使组件复用变得困难

  • 提供四个API

    • React.createContext

    • Context.Provider

    • Class.contextType

    • Context.Consumer

  • Context 简单使用

    // light 为 defaultValue 仅在当一个组件在组件树中没有匹配到the closest Provider
    // 可以 传属性、方法 
    const ThemeContext = React.createContext('light');
    class App extends React.Component {
        render() {
        // Use a Provider to pass the current theme to the tree below.
        // Any component can read it, no matter how deep it is.
        // In this example, we're passing "dark" as the current value.
        return (
          <ThemeContext.Provider value="dark">
            <Toolbar />
          </ThemeContext.Provider>
        );
      }
    }
    ​
    // A component in the middle doesn't have to
    // pass the theme down explicitly anymore.
    function Toolbar(props) {
      return (
        <div>
          <ThemedButton />
        </div>
      );
    }
    // Consumer两种写法
    class ThemedButton extends React.Component {
      // Assign a contextType to read the current theme context.
      // React will find the closest theme Provider above and use its value.
      // In this example, the current theme is "dark".
      static contextType = ThemeContext;
      render() {
        return <Button theme={this.context} />;
      }
    }
    class ThemedButton extends React.Component {
        render() {
            return (
                <ThemeContext.Consumer>
                    {value => (
                        <Button theme={value} />
                    )}
                </ThemeContext.Consumer>
            );
        }
    }
  • 一个生产者多个消费者

    • 1 Context.Provider

    • n Context.Consume

  • Provider 值属性改变时,Consume将重新render。从Provider到Consume的传播不受shouldComponentUpdate方法约束。

  • Consume 可以通过 static contextType = ThemeContext ,然后使用 this.context获取到the closest Provider的value值

  • Consume 可以使用

    <Context.Consumer>
        {value => /* render something based on the context value */}
    </Context.Consumer>
  • Consuming Multiple Contexts

    • 多层Provider ,多层Consumer 嵌套

Error Boundaries

  • Error boundaries do not catch errors for:

    • Event handlers (learn more)

    • Asynchronous code (e.g. setTimeout or requestAnimationFrame callbacks)

    • Server side rendering

    • Errors thrown in the error boundary itself (rather than its children)

  • A class component becomes an error boundary if it defines either (or both) of the lifecycle methods static getDerivedStateFromError() or componentDidCatch().

    • Use static getDerivedStateFromError() to render a fallback UI after an error has been thrown. Use componentDidCatch() to log error information.

  • Error Boundaries 简单使用

    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false };
      }
    ​
      static getDerivedStateFromError(error) {
        // Update state so the next render will show the fallback UI.
        return { hasError: true };
      }
    ​
      componentDidCatch(error, info) {
        // You can also log the error to an error reporting service
        logErrorToMyService(error, info);
      }
    ​
      render() {
        if (this.state.hasError) {
          // You can render any custom fallback UI
          return <h1>Something went wrong.</h1>;
        }
    ​
        return this.props.children; 
      }
    }

Forwarding Refs

  • API React.forwardRef

    const FancyButton = React.forwardRef((props, ref) => (
      <button ref={ref} className="FancyButton">
        {props.children}
      </button>
    ));
    ​
    // You can now get a ref directly to the DOM button:
    // 此处便获取了 button 的 引用
    const ref = React.createRef();
    <FancyButton ref={ref}>Click me!</FancyButton>;
  • 使父组件可以获取子组件的引用,即可获取子组件实体,调用子组件的方法

Higher-Order Components

  • 复用组件逻辑时使用

  • 不要在 render 方法中使用 HOCs ,当更新时,会完整的卸载之前的组件树

Portals

  • API ReactDOM.createPortal(child, container)

  • 使用场景 a parent component has an overflow: hidden or z-index style, but you need the child to visually “break out” of its container. For example, dialogs, hovercards, and tooltips.

  • 事件冒泡能通过 portals 继续向上

Reconciliation

  • 主要解释了 React’s “diffing” algorithm

    • Elements Of Different Types 元素类型不同,销毁旧的构建新的

    • DOM Elements Of The Same Type 元素类型相同,比较元素的属性,属性不同只更新属性

    • Component Elements Of The Same Type 组件元素类型相同,React更新props以匹配新元素,并调用componentWillReceiveProps()andcomponentWillUpdate()

Refs and the DOM

  • Refs 提供一种能够获取Dom节点或者组件的方法

    • 经典的React数据流:props是父组件影响子组件的唯一方式,为了修改子组件,需要用新的props re-render子组件

  • 什么时候使用

    • Managing focus, text selection, or media playback. 获取焦点,文本选择,媒体的播放

    • Triggering imperative animations. 触发动画

    • Integrating with third-party DOM libraries. 与第三方dom库整合

  • 可以被声明式的写时 避免使用ref

  • 不能使用ref在function components,因为它没有实例

  • 生命周期中 ref的状况

    • 当组件 mounts时,React将current property分配给 dom元素

    • 当组件 unmounts时, 返回 null

    • Ref updates 在componentDidMountorcomponentDidUpdate 之前

Render Props

  • 复用 状态和行为 给其它需要相同状态和行为的组件

  • 例子,鼠标移动时,分享坐标值给各个组件

    class Cat extends React.Component {
      render() {
        const mouse = this.props.mouse;
        return (
          <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
        );
      }
    }
    class Mouse extends React.Component {
      constructor(props) {
        super(props);
        this.handleMouseMove = this.handleMouseMove.bind(this);
        this.state = { x: 0, y: 0 };
      }
    ​
      handleMouseMove(event) {
        this.setState({
          x: event.clientX,
          y: event.clientY
        });
      }
    ​
      render() {
        return (
          <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
    ​
            {/* ...but how do we render something other than a <p>? */}
            this.props.children(this.state)
          </div>
        );
      }
    }
    ​
    class MouseTracker extends React.Component {
      render() {
        return (
          <div>
            <h1>Move the mouse around!</h1>
            {/* children prop doesn’t actually need to be named in the list of “attributes” in your JSX element */}
            <Mouse>
             {mouse => <Cat mouse={mouse} />}    
            </Mouse>
          </div>
        );
      }
    }
    ​
    // 也可以使用 HOC
    function withMouse(Component){
        return class extends React.Component {
            render(){
                return (
                    <Mouse>
                        {mouse => <Component {...this.props} mouse={mouse} />}
                    </Mouse>
                )
            }
        }
    }
    ​

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值