React基础学习

JSX

为了便于阅读,建议将jsx拆分为多行,并且将内容用()包裹,这可以避免遇到自动插入分号陷阱。

注:自动插入分号ASI(auto semicon insertion)

\r(回车符), \n(换行符),\r\n的区别

在以 ([/+- 开头的语句前加分号

尤大解读

React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。class 变为className , tabindex 变为tabIndex。

JSX可以防止 XSS(cross-site-scripting, 跨站脚本)攻击。

Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。

以下两种代码完全等效:

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

元素渲染

想要将一个元素渲染到跟DOM节点中,只需把它们一起传入 ReactDOM.render()

React 元素是不可变对象

考虑 UI 在任意给定时刻的状态,而不是随时间变化的过程,能够消灭一整类的 bug。

组件&Props

React 元素也可以是用户自定义的组件

注意: 组件名称必须以大写字母开头。

从组件自身的角度命名 props,而不是依赖于调用组件的上下文命名。

所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

纯函数:不会尝试更改入参,且多次调用下相同的入参始终返回相同的结果。

function sum(a, b) {
  return a + b;
}

State & 生命周期

react class方式声明:

  1. 先调用constructor初始化state
  2. 调用render函数渲染DOM元素
  3. 调用相关生命周期方法

当State中的某个状态发生变化,我们应该重新创建这个状态对象,而不是直接修改原来的状态。

正确渲染state:

  1. 调用setState()方法来更新state的状态,且构造函数是唯一可以给this.state赋值的地方

  2. state的更新可能是异步的

    出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。

    this.setState(function(state, props) {
      return {
        counter: state.counter + props.increment
      };
    });
    
  3. 当你调用 setState() 的时候,React 会把你提供的对象合并到当前的 state。组件State的更新是一个浅合并的过程。

深入React组件状态

任何的 state 总是所属于特定的组件,而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。

事件处理

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

如果需要组织事件的默认行为,必须显式的调用 preventDefault

引出

事件委托

事件循环机制

MutationObserver

宏任务和微任务

堆栈

javascript bind()

绑定事件处理函数作用域的方式

  • 利用bind方法

    constructor(props) {
        super(props);
        this.state = {isToggleOn: true};
    
        // 为了在回调中使用 `this`,这个绑定是必不可少的
        this.handleClick = this.handleClick.bind(this);
      }
    
  • 你可以在回调中使用箭头函数,不推荐,每次会创建一个新的函数,当做参数传入子组件,可能会进行额外的重新渲染

       // 此语法确保 `handleClick` 内的 `this` 已被绑定。
    render() {
        return (
          <button onClick={(e) => this.handleClick(e)}>
            Click me
          </button>
        );
      }
    
  • class fields 语法

    // 此语法确保 `handleClick` 内的 `this` 已被绑定。
      // 注意: 这是 *实验性* 语法。
      handleClick = () => {
        console.log('this is:', this);
      }
    

向事件处理程序传递参数

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

使用箭头函数绑定事件时,需要显示传递事件对象e

条件渲染

与运算符 &&

return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );

在 JavaScript 中,true && expression 总是会返回 expression, 而 false && expression 总是会返回 false

在极少数情况下,你可能希望能隐藏组件,即使它已经被其他组件渲染。若要完成此操作,你可以让 render 方法直接返回 null,而不进行任何渲染。

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return (
    <div className="warning">
      Warning!
    </div>
  );
}

在组件的 render 方法中返回 null 并不会影响组件的生命周期。

列表 & Key

key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。

给数组元素赋予确定标识的方式

  • 使用元素的id

  • 使用索引index。如果你选择不指定显式的 key 值,那么 React 将默认使用索引用作为列表项目的 key 值。如果列表项目的顺序可能会变化,我们不建议使用索引来用作 key 值,因为这样做会导致性能变差,还可能引起组件状态的问题。example

    const todoItems = todos.map((todo, index) =>
      // Only do this if items have no stable IDs
      <li key={index}>
        {todo.text}
      </li>
    );
    

元素的 key 只有放在就近的数组上下文中才有意义。即放在数组元素上,不论数组元素是原生标签还是自定义组件。

这个 key 不需要全局唯一,但在列表中需要保持唯一。

key 会传递信息给 React ,但不会传递给你的组件。如果你的组件中需要使用 key 属性的值,请用其他属性名显式传递这个值:

const content = posts.map((post) =>
  <Post
    key={post.id}
    id={post.id}
    title={post.title} />
);

如果一个 map() 嵌套了太多层级,那可能就是你提取组件的一个好时机。

引出

算法时间复杂度 算法复杂度分析

React 在以下两个假设的基础之上提出了一套 O(n) 的启发式算法:

  1. 两个不同类型的元素会产生出不同的树;
  2. 开发者可以通过 key prop 来暗示哪些子元素在不同的渲染下能保持稳定;

Diffing算法

react diff算法 react diff算法源码分析

react tree diff 在处理层级移动时,会重新创建整个层级,影响性能。可以使用CSS显示或隐藏节点,而不是真的添加和删除节点。

在开发过程中,尽量减少类似将最后一个节点移动到列表首部的操作,当节点数量过大或更新操作过于频繁时,在一定程度上会影响 React 的渲染性能。

表单

当需要处理多个 input 元素时,我们可以给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作。

受控组件上指定 value 的 prop 可以防止用户更改输入。如果指定了 value,但输入仍可编辑,则可能是意外地将value 设置为 undefinednull

react表单组件

受控组件

  • 设置value/checked属性
  • 设置onChange事件

非受控组件

  • 默认值通过defaultValue来进行设置
  • 使用 ref 来从 DOM 节点中获取表单数据

在 React 中,<input type="file" /> 始终是一个非受控组件,因为它的值只能由用户设置,而不能通过代码控制。

引出

使用受控组件的条件

  • 就地反馈,如表单即时验证
  • 除非所有的字段都有效,否则禁用提交按钮
  • 强制执行特定的输入格式,如信用卡号码

如何选用受控组件和非受控组件

refs

  • ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性。
  • ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性。
  • 你不能在函数组件上使用 ref 属性,因为他们没有实例。你可以在函数组件内部使用 ref 属性,只要它指向一个 DOM 元素或 class 组件

Ref 转发使组件可以像暴露自己的 ref 一样暴露子组件的 ref

回调方式

  • 构造器中声明一个变量,在组件挂载完成后,调用生命周期方法,赋予这个变量对应的元素

通过React.createRef()方式创建

  • 当 ref 被传递给 render 中的元素时,对该节点的引用可以在 ref 的 current 属性中被访问。
  • 通过在ref组件中调用 React.forwardRef()API实现ref的转发 ref传递

状态提升

你应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state。

虽然提升 state 方式比双向绑定方式需要编写更多的“样板”代码,但带来的好处是,排查和隔离 bug 所需的工作量将会变少。

如果某些数据可以由 props 或 state 推导得出,那么它就不应该存在于 state 中。

React 开发者工具

组合 vs 继承

特殊prop属性children ,类似于Vue中的插槽

实现具名插槽

function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {props.left}
      </div>
      <div className="SplitPane-right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <SplitPane
      left={
        <Contacts />
      }
      right={
        <Chat />
      } />
  );
}

常用于组件复用UI功能

对于非UI功能的复用,组件可以直接引入(import)而无需通过 extend 继承它们。

posted @ 2019-05-31 15:24  CodingSherlock  阅读(211)  评论(0编辑  收藏  举报