React笔记

了解jsx

1.jsx只是一种语法糖,编译器会对应编译为React.createElement(component, props, …children),如

<MyButton color="blue" shadowSize={2}>
    Click me
</MyButton>

会被编译为

React.createElement(MyButton, {color:"blue", shadowSize:2}, "Click me"}

2.自定义组件必须大写开头,否则会被识别为内置组件,如以下代码会导致编译失败,另外自定义组件必须引入React。

<div></div>

如果自定义组件为小写,或者使用表达式选择组件,则必须先赋值给大写开头的变量,然后才可以在jsx中作为自定义组件使用

3.props使用
可以用{}包裹表达式作为prop,如

<MyComponent foo={1+2+3} />

if/loop等不能直接用于jsx中,可以先计算表达式结果之后在jsx中使用。

<MyTextView autcomplete />

等价于

<MyTextView autocomplete={true}/> 

如果已经有现成props,可以使用{…props}作为props传入jsx,如果不希望传入全部props,可以指定部分不传入,比如

const props = {first:"primary", second:"second"};
return <MyButton {first, ...props}/>

4.在jsx表达式中,tag间的内容会赋值给一个特殊的prop: props.children
children可以是普通字符串,也可以是嵌套的组件
React组件也可以返回一组element,如

render() {
	return [
		<li key="a">A</li>,
		<li key="b">B</li>,
	]
}

children也可以是{}包裹的表达式
children也可以是function,组件可以在render中调用function生成对应的jsx代码
children为true/false,null,undefined均被忽略,不会渲染

类型检查

针对组件的prop 类型检查,可以给属性propTypes赋值,如

import PropTypes from 'prop-types';

class Greeting extends React.Component {
	render() {
		return (
			<h1>Hello, {this.props.name}</h1>
		);
	}
}
Greeting.propTypes = {name:PropTypes.string}; //name为字符串类型

静态检测

TypeScript作为有类型的js超集,可以在应用构建时发现错误。
1.添加TypeScript

npm install --save-dev typescript

之后就可以使用tsc命令,一般将它添加到package.json的scripts中

{
     “scripts”{
     “build”:”tsc”,
     //...
    }
}

2.配置编译器
编译规则定义在tsconfig.json文件中,可以通过如下命令生成

tsc --init

我们主要需要配置其中的rootDir和outDir项,即源代码目录及编译后输出目录。另外outDir一般需要放入.gitignore中。

3.文件后缀名
普通文件后缀名为.ts,带有jsx的文件后缀名为.tsx

4.运行TypeScript

npm run build

5.类型定义
编译器依赖如类型声明来显示错误,对于一个库,类型声明的方式有三种:

  • bundled 库中打包了类型声明文件,一般为index.d.ts文件,有些会在package.json中的typings或者types中指定
  • DefinitelyTyped 一个远程仓库,托管一些常见库的类型声明,比如React库

npm i --save-dev @types/react

  • 如果使用的库没有声明文件,也无法从DefinitelyTyped中获取,则可以自己添加一个声明文件declarations.d.ts,例如

declare module ‘querystring’ {
export function stringify(val: object): string
export function parse(val: string): object
}

refs & dom

refs提供了一种访问在render方法中创建的dom节点或React组件的方式。下面几种场景适合使用refs

  • 处理焦点、文本选择、媒体控制
  • 触发强制动画
  • 集成第三方dom库

1.新建refs
refs一般使用React.createRef()创建,然后在组件的构造方法中赋值给一个property,这样就可以在整个组件中引用到,可以在渲染时用ref参数附加到element上。

class MyComponent extends React.Component{
    constructor(props){
        super(props)
        this.myRef = React.createRef();
    }
    render() {
        return (
            <div ref={this.myRef}/>
        );
    }
}

2.访问refs
在render方法中将ref传给element后,可以使用ref的参数current来引用该节点。

const node = this.myRef.current;

当ref用在HTML element上时,current表示该element,当ref用在普通的class组件上时,current表示该组件的实例。
不可以在函数式组件中使用ref因为函数式组件没有实例。
3.callback refs
除了设置在组件中设置属性ref为React.createRef()的结果外,还可以设置属性ref为一个函数,该函数会传入当前组件实例或者dom。React会在调用componentDidMount前调用该函数。
callback refs可以在组件之间传递,比如parent可以定义一个function作为prop传入child,该function中获取ref保存到自身的变量childNode中,child在render方法中将该function作为组件input的ref参数,这样childNode就引用了child中的input节点。

function CustomTextInput(props) {
  return (
    <div>      <input ref={props.inputRef} />    </div>
  );}
class Parent extends React.Component {
  render() {
    return (
      <CustomTextInput        inputRef={el => this.inputElement = el}      />
    );
}}

非受控组件

受控组件中,表单数据由React组件处理,对应的非受控组件中,表单数据由dom处理。
实现一个非受控组件,不需要为每个状态写一个事件回调,可以直接使用ref从dom中取得表单数据。比如



class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.input.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={(input) => this.input = input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

默认值

表单元素的value参数会覆盖dom的value,在使用非受控组件时,如果希望表单元素有默认值,但是又不希望后续后续dom value的改变被覆盖。此时可以为表单元素设置参数defaultValue。



render() {
  return (
    <form onSubmit={this.handleSubmit}>
      <label>
        Name:
        <input
          defaultValue="Bob"
          type="text"
          ref={(input) => this.input = input} />
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
}

同样地,checkbox和radio元素支持defaultChecked,select和textarea元素支持defaultValue。

文件输入标记

在HTML中,<input type="file">可以让用户从设备存储中选择一个或者多个文件上传到服务器中,或通过File API进行操作。
在React中,<input type="file">始终是一个不受控制的组件,它的值只能由用户设置。
以下代码演示如何创建ref节点以访问提交处理程序中的文件

class FileInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleSubmit(event) {
    event.preventDefault();
    alert(
      `Selected file - ${this.fileInput.files[0].name}`
    );
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Upload file:
          <input
            type="file"
            ref={input => {
              this.fileInput = input;
            }}
          />
        </label>
        <br />
        <button type="submit">Submit</button>
      </form>
    );
  }
}

ReactDOM.render(
  <FileInput />,
  document.getElementById('root')
);

性能优化

使用生产编译

可以在chrome中安装React Developer Tools for Chrome插件来检测网站是否为生产编译版本。绿色背景图标为生产版本,红色背景图标为开发模式。
以webpack为例描述如何编译生产版本,在生产配置中包含如下插件

// 配置仅用于生产环境,不可以用于开发环境,否则会隐藏有用的警告,同时会使编译更慢
new webpack.DefinePlugin({
    'process.env.NODE_ENV':JSON.stringify('production')
}),
new webpack.optimize.uglifyJsPlugin()

更多可以参考官方文档webpack文档

使用Chrome 性能 选项优化组件

在开发模式下,借助浏览器的性能分析工具开发人员可以看到组件是如何挂载,更新,卸载的。
在chrome中操作如下

  1. 临时停用所有chrome插件,特别是React DevTools,因为这些插件可能影响结果
  2. 确保应用出于开发模式
  3. 打开Chrome DevTools 中性能选项卡,点击Record
  4. 操作希望优化的场景,时间控制在20s内
  5. 停止录制
  6. React事件会展示在User Timing标签下

虚拟化长列表

长列表可以采用windowing技术,使用该技术后只需要渲染一定数量的数据,同时可以减少创建dom节点和刷新组件的时间。React VirtualIzed是一种流行的windowing库,它为展示列表,表格等数据提供了一种可复用的组件。开发人员也可以创建自定义的windowing组件。

避免重复渲染

React内部创建并维护当前已渲染ui的实现,它包含了组件中返回的React elements。这种实现方式使得React避免了一些不需要的创建和关联dom节点。有时它被称为虚拟dom。
当一个组件的props或者state改变时,React会将新返回的element和原有的进行比较,不一致时React才会更新dom。
可以通过React DevTools看到虚拟dom的重复渲染
chrome插件
firefox插件
在开发者控制台勾选React选项卡中的"Highlight Updates"选项,操作页面时渲染的组件会显示闪动的边框。针对不需要重复渲染的组件,开发人员应该重写shouldComponentUpdate方法,该方法会在触发渲染前调用,默认返回true,即React会进行刷新。

shouldComponentUpdate(nextProps, nextFocus) {
	return true;
}

如果明确知道该组件不需要刷新,开发人员应该重写该方法并返回false。大多数情况下,开发人员可以继承React.PureComponent。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值