初识React你应该知道的一些点

2020-09-29  本文已影响0人  LinDaiDai_霖呆呆

前言

你盼时间,我盼望你无bug。Hello 大家好,我是霖呆呆!
噗...没啥好说的,忍住,看文章吧[哭笑~]

组件

组件允许你将UI拆分为独立可复用的代码片段,每个片段进行独立构思。

组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。

以上两个组件是等效的。

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

React 会将以小写字母开头的组件视为原生 DOM 标签。例如,代表 HTML 的 div 标签,而 则代表一个组件,并且需在作用域内使用 Welcome

State

正确的使用setState()

事件

解决事件中this绑定的问题,如果不想用bind显式绑定的话,可以使用下面两种方式:

组合VS继承

React中并没有类似于Vue中的slot,不过可以靠prop来实现:

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 />
      } />
  );
}

语法需要注意的点

1. 数字0依旧会被渲染

false, null, undefined是合法的子元素,但它们并不会渲染,因此可以作为判断JSX表达式渲染结果:

<div>
  {showHeader && <Header />}
  <Content />
</div>

但是数字0,仍然会被 React 渲染。例如,以下代码并不会像你预期那样工作,因为当 props.messages 是空数组时,0 仍然会被渲染:

<div>
  {props.messages.length &&
    <MessageList messages={props.messages} />
  }
</div>

解决方式:确保 && 之前的表达式总是布尔值:

<div>
  {props.messages.length > 0 &&
    <MessageList messages={props.messages} />
  }
</div>

2. 元素和组件

元素:React 元素是构成 React 应用的基础砖块。元素描述了你在屏幕上想看到的内容。React 元素是不可变对象。例如:

const element = <h1>Hello, world</h1>;

组件:React 组件是可复用的小的代码片段,它们返回要在页面中渲染的 React 元素。例如:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

如何阻止组件不更新

以下生命周期默认是返回true,只要将其改为false即不更新。

shouldComponentUpdate(nextProps, nextState) {
    return false;
  }

其它API

在组件上能调用的方法

不同于上述生命周期方法(React 主动调用),以下方法是你可以在组件中调用的方法。

只有两个方法:setState()forceUpdate()

forceUpdate()强制组件重新渲染

默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 render() 方法依赖于其他数据,则可以调用 forceUpdate() 强制让组件重新渲染。

调用 forceUpdate() 将致使组件调用 render() 方法,此操作会跳过该组件的 shouldComponentUpdate()

但其子组件会触发正常的生命周期方法,包括 shouldComponentUpdate() 方法。如果标记发生变化,React 仍将只更新 DOM。

注意⚠️:

通常你应该避免使用 forceUpdate(),尽量在 render() 中使用 this.propsthis.state

Class属性

defaultProps

defaultProps 可以为 Class 组件添加默认 props。这一般用于 props 未赋值,但又不能为 null 的情况:

class CustomButton extends React.Component {
  // ...
}

CustomButton.defaultProps = {
  color: 'blue'
};

上述CustomButton被调用时如果没有提供props.color,则默认为blue

此时如果传递了null的话,则就会是null

render() {
  return <CustomButton color={null} /> ; // props.color 将保持是 null
}

displayName

displayName 字符串多用于调试消息。通常,你不需要设置它,因为它可以根据函数组件或 class 组件的名称推断出来。

用处

调试时需要显示不同的名称或创建高阶组件。displayName可以方便我们在使用Chrome浏览器插件的情况下通过审查元素看到具体是哪个组件。

例如你要审查的这个元素是一个HOC产物,如下一个简单的案例🌰:

LoginHOC.tsx:

import React, { Component } from 'react';

export default function LoginHoc (WrappedComponent) {
  class InnerComponent extends Component {
    render () {
      return (
        <WrappedComponent {...this.props}></WrappedComponent>
      )
    }
  }
  return InnerComponent;
}

Blog.tsx:

import React, { Component } from 'react';
import LoginHOC from './LoginHOC';

class Blog extends Component {
  render () {
    return (
      <div className='blog'>
        <button>我是按钮</button>
      </div>
    )
  }
}

export default LoginHOC(Blog);

App.js中引用:

import Blog from './components/HOC-example/Blog';

function App () {
  return (
    <div className='App'>
      <Blog detail={1}></Blog>
    </div>
  )
}
export default App;

这时候使用Chrome插件React Developer Tools调试时,会发现页面中的元素为这样:

r1.png

此时如果你给HOC设置了displayName的话:

import React, { Component } from 'react';

export default function LoginHoc (WrappedComponent) {
  class InnerComponent extends Component {
    render () {
      return (
        <WrappedComponent {...this.props}></WrappedComponent>
      )
    }
  }
+ InnerComponent.displayName = `LoginHoc(${getDisplayName(WrappedComponent)})`;
  return InnerComponent;
}
+ function getDisplayName (WrappedComponent) {
+  return WrappedComponent.displayName || WrappedComponent.name || 'Component'
+}

效果如下:

r2.png

能更加清楚的让我们看到包装显示名称。

ReactDOM

react-dom 的 package 提供了可在应用顶层使用的 DOM(DOM-specific)方法,如果有需要,你可以把这些方法用于 React 模型以外的地方。不过一般情况下,大部分组件都不需要使用这个模块。

DOM相关

className

className 属性用于指定 CSS 的 class,此特性适用于所有常规 DOM 节点和 SVG 元素,如 及其它标签。

如果你在 React 中使用 Web Components(这是一种不常见的使用方式),请使用 class 属性代替。

dangerouslySetInnerHTML

dangerouslySetInnerHTML 是 React 为浏览器 DOM 提供 innerHTML 的替换方案。通常来讲,使用代码直接设置 HTML 存在风险,因为很容易无意中使用户暴露于跨站脚本(XSS)的攻击。

使用:

设置一个带有属性名为key的对象:

function createMarkup() {
  return {__html: 'First &middot; Second'};
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}
  
// 使用
<MyComponent></MyComponent>

最终会被渲染为:

First · Second

style

style属性接收的是一个对象,这点和DOMstyleJavaScript属性一样,同时会更高效的,且能预防跨站脚本(XSS)的安全漏洞。例如:

const divStyle = {
  color: 'blue',
  backgroundImage: 'url(' + imgUrl + ')',
};

function HelloWorldComponent() {
  return <div style={divStyle}>Hello World!</div>;
}

需要注意的点:

合成事件

我们知道在普通的DOM元素中有一个event对象来获取事件对象。

而在React中,获取到的这个事件对象被称为合成事件SyntheticEvent

它是浏览器的原生事件的跨浏览器包装器。除兼容所有浏览器外,它还拥有和浏览器原生事件相同的接口,包括 stopPropagation()preventDefault()

每个 SyntheticEvent 对象都包含以下属性:

boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
boolean isDefaultPrevented()
void stopPropagation()
boolean isPropagationStopped()
void persist()
DOMEventTarget target
number timeStamp
string type

事件池

如上所述,SyntheticEvent是一个合成事件,如果我们在事件的回调函数中直接打印它出来,获取到的属性值全都是null或者undefined

例如这段代码:

import React, { Component } from 'react';

export default class SyntheticEvent extends Component {
  clickBtn (event) {
    console.log(event); // nullified object
    console.log(event.type); // "click"
  }
  render () {
    return (
      <>
        <button onClick={this.clickBtn.bind(this)}>
          点击我
        </button>
      </>
    )
  }
}

event拿到的对象:

{
 detail: null,
 type: null,
 nativeEvent: null,
 isTrusted: null,
 ...
}

所以有了官网的这句话:

SyntheticEvent 是合并而来。这意味着 SyntheticEvent 对象可能会被重用,而且在事件回调函数被调用后,所有的属性都会无效。出于性能考虑,你不能通过异步访问事件。

再如下:

function clickBtn(event) {
  console.log(event); // => nullified object.
  console.log(event.type); // => "click"
  const eventType = event.type; // => "click"

  setTimeout(function() {
    console.log(event.type); // => null
    console.log(eventType); // => "click"
  }, 0);

  // 不起作用,this.state.clickEvent 的值将会只包含 null
  this.setState({clickEvent: event});

  // 你仍然可以导出事件属性
  this.setState({eventType: event.type});
}

如果你想异步访问事件属性,你需在事件上调用 event.persist(),此方法会从池中移除合成事件,允许用户代码保留对事件的引用。

clickBtn (event) {
  event.persist()
  console.log(event);
  console.log(event.type);
}

现在的event

{
 detail: 1,
 type: 'click',
 nativeEvent: {...},
 isTrusted: true,
 ...
}

处理捕获阶段的点击事件

处理捕获阶段的点击事件请使用 onClickCapture,而不是 onClick

上一篇下一篇

猜你喜欢

热点阅读