React - Medium Knowledge

React - 进阶详解

提供一个在线编辑器:react
https://codesandbox.io/s/new

一、JSX深入理解

JSX只是React.createElement(component,props,...children)的语法糖

//JSX
import React from 'react';//必须引入
.........

<Greeting date={2} name="cindy"/>
__________________________________
编译后JSX会调用

React.createElement(
    Greeting,
    {data: 2, name: "cindy" },
    null
)

1.JSX标签

1)大写的 JSX 标签名代表一个 React 组件,若是小写字母,表示JSX内置的组件

2) JSX编译首先会调用React.creteElement(),所以JSX必须现调用
es6: import React from 'react';
es5: var React = require('react')

3) 点表示法:可以任意从一个模块中调出任意一个组件

import React from 'react';
const myComponent = {
    picker:function(props){
            return <h1>children get a props {props.cololr}</h1>
    }

}

class blueDatePicker

4)不能用表达式作为React 元素的标签

`


2.JSX属性的表达方式
注意:在react中,没有class属性,替代为className属性

1.javascript表达式
你可以传递任何 {} 包裹的 JavaScript 表达式作为一个属性值,这个表达式会自动计算最后的结果。 <MyComponent foo={1 + 2 + 3 + 4} />

注意 :在JSX中if语句和for语句不能使用,因为不是JSX表达式

2.字符串

 <MyComponent message={'hello world'} />
 <MyComponent message="hello world" />

3.扩展属性{…props}

如果有了个 props 对象,并且想在 JSX 中传递它,你可以使用 … 作为扩展操作符来传递整个属性对象。下面两个组件是等效的:

function Greeting() {
  return <Greeting firstName="Cindy" lastName="Stella" />;
}

function World() {
  const props = {firstName: 'Ben', lastName: 'Hector'};
  return <Greeting {...props} />;
}

3.子代
props.children - 一个标签内的子元素

4.JSX - 嵌套元素


二、React.Component - lifecycles

React的Compoent组件将react的UI界面分割成一个个组件。
Component最重要的就是生命周期(lifecycles),生命周期分为3个阶段:初始化、更新、卸载
这里写图片描述
如图,可以把组件生命周期大致分为三个阶段:

第一阶段:是组件第一次绘制阶段,如图中的上面虚线框内,在这里完成了组件的加载和初始化;
第二阶段:是组件在运行和交互阶段,如图中左下角虚线框,这个阶段组件可以处理用户交互,或者接收事件更新界面;
第三阶段:是组件卸载消亡的阶段,如图中右下角的虚线框中,这里做一些组件的清理工作。

1.创建时(初始化组件):
constructor() - getInitialState
defaultProps - getDefaultProps
componentWillMount()
render()
componentDidMount()

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      age: 12
    };
  }
  componentWillMount() {
    console.log("componentWillmount");
  }

  render() {
    console.log("render");
    return <h1>{this.props.name}</h1>;
  }
  componentDidMount() {
    console.log("componentDidMount");
  }
}

App.defaultProps = {
  name: "this.is life cycle test"
};

2.更新时:
render()
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
componentDidUpdate()

2.1 state更新
updating State
ShouldComponentUpdate()
componentWillUpdate()
render()
ComponentDidUpdate()

2.2 props更新
updateing Props
ComponentWillReciveProps()
shouldComponentUpdate()
ComponentWillUpdate()
render()
ComponentDidUpdate()

3.卸载时:
componentWillUnmount()

4.详细介绍:
1.render()
更新UI界面的方法
该方法是必须的,有一个return 返回。
创建虚拟DOM,进行diff算法,更新DOM树都要在render()方法中进行

2.constructor(props)
构造函数,在创建组件的时候调用一次。
React组件的构造函数将会在render()之前被调用。当为一个React.Component子类定义构造函数时,你应该在任何其他的表达式之前调用super(props)。否则,this.props在构造函数中将是未定义,并可能引发异常。

3.ComponentWillMount()

在组件初始化之前调用一次,组件更新时不调用。如果在这个函数里面调用setState,本次的render函数可以看到更新后的state,并且只渲染一次。

4.componentDidMount()
在组件挂载之后调用一次。这个时候,子主键也都挂载好了,可以在这里使用refs。
若你需要从远端加载数据,这是一个适合实现网络请求的地方。在该方法里设置状态将会触发重新渲染。

5.componentWillReceiveProps(nextProps)
组件初始化时不调用,组件接受新的props时调用。

6.shouldComponentUpdate(nextProps,nextState) {}
该方法总是在render()之前被唤起,但不会在初始化组件执行
react性能优化非常重要的一环。组件接受新的state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,这样就不需要创造新的dom树和旧的dom树进行diff算法对比,节省大量性能,尤其是在dom结构复杂的时候.
总是返回 :return true;//return false;

7.componentWillUpdate(nextProps,nextState) {}
当shouldComponentUpdate函数返回true时,componentWillUpdate()为在渲染前被立即调用。在更新发生前,使用该方法是一次准备机会。该方法不会在初始化渲染时调用。

注意你不能在这调用this.setState(),若你需要更新状态响应属性的调整,使用componentWillReceiveProps()代替。

注意:
若shouldComponentUpdate()返回false,componentWillUpdate()将不会被调用。

8.ComponentDidUpdate(prevProps,prevState) {}
componentDidUpdate()会在更新发生后(render方法之后)立即被调用。该方法并不会在初始化渲染时调用。

当组件被更新时,使用该方法是操作DOM的一次机会。这也是一个适合发送请求的地方,要是你对比了当前属性和之前属性(例如,如果属性没有改变那么请求也就没必要了)。
若shouldComponentUpdate()返回false,componentDidUpdate()将不会被调用。

9.componentWillUnmount(){}
componentWillUnmount()在组件被卸载和销毁之前立刻调用。可以在该方法里处理任何必要的清理工作,例如解绑定时器,取消网络请求,清理任何在componentDidMount环节创建的DOM元素。

测试代码:

//可在项目中测试使用
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      age: 12
    }
    alert("initial render");
    alert("constructor");
  }

  componentWillMount() {
    alert("componentWillMount");
    alert(this.state.age);
  }

  componentDidMount() {
    alert("componentdidMout");
    this.setState({
      age: 33
    });
  }

  componentWillUnmount() {
    alert("componentWillUnmounted");
  }

  ComponentWillUpdate() {
    alert("componentWILLuPDATE");
  }

  componentWillReceiveProps(nextProps) {

  }

  shouldComponentUpdate(nextProps,nextState) {
      alert("shouldComponentUpdate");
      console.log(nextState);
      return true; //必须写词一部
      //return false;若为false,不会进行任何后续更新state 操作

  }

  componentWillUpdate(nextProps,nextState) {
    alert("compoentWillUpdate");
  }

  componentDidUpdate(prevProps,prevState) {
    alert("componentDidUpdate");
  }
  render() {
    alert("render");
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        <p>{this.state.age}</p>
      </div>
    );
  }
}


export default App;

三、Refs & DOM

React支持给任意组建添加特殊属性,其中就有ref属性。
ref属性接受一个回调参数,他在组件被加载和卸载时被调用

1.DOM元素添加ref 属性

class App extends Component {
  constructor(props) {
    super(props);
    this.changeFocus = this.changeFocus.bind(this);
  }

  changeFocus() {
    this.input.focus();
  }
  render() {
    return (
      <div className="App">
        <form>
          <input 
            type="text"
            ref={(input) => this.input = input }
            />
            <input 
              type="text"
              value="hello"
              onFocus = {this.changeFocus}
              />
        </form>
      </div>
    );
  }
}

注:ref 回调参数中:接收 底层DOM元素 作为参数,
所以上述代码中,ref中的参数是<input/>

2.类组件添加ref
当 ref 属性用于使用 class 声明的自定义组件时,ref 的回调接收的是已经加载的 React 实例。

class AutoFocusTextInput extends React.Component {
  componentDidMount() {
    this.textInput.focusTextInput();
  }

  render() {
    return (
      <CustomTextInput
        ref={(input) => { this.textInput = input; }} />
    );
  }
}

3.用 函数声明的组件 不能绑定ref属性


四、不使用Es6

因各大浏览器已兼容ES6,此作为了解:http://www.css88.com/react/docs/react-without-es6.html


五、不适用JSX

react 的语法糖就是使用JSX,不使用仅作了解:http://www.css88.com/react/docs/react-without-jsx.html


六、使用PropsTypes检查属性类型

import PropTypes from 'prop-types';

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

Greeting.propTypes = {
  name: PropTypes.string
};

注意:protoytypes直再开发模式下进行检查


七、uncontrolled Components / controlled Components

都用于表单元素,两者区别:表单数据是交给react组件处理(受控组件),还是让表单数据交给DOM元素处理(非受控组建)

6.1非受控组建 - 使用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>
    );
  }
}

1)默认值 - defaultvalue
因为在react生命周期中,表单中value属性会覆盖DOM中的value。
defaultValue - react的初始值。和后续DOM中的值无关

input :radio/checkbox 支持defaultValue
select textarea: 支持defaulteValue

//1.input - text/textarea
class App extends React.Component{
  handelData(){
    alert(`data :${this.textInput.value}`)
  }
  render(){
    return(
      <form onSubmit={this.handelData.bind(this)}>
        <label>name</label>
        <input type="text" 
                ref={(input) => this.textInput = input}
                defaultValue={"name"}/>
        <br/>
        <input type="submit" value="submit"/>
      </form>
    );
  }
}
//2.input - radio/checkbox
class App extends React.Component {
  handelData() {
    alert(`data :${this.textInput.value}`);
  }
  render() {
    return (
      <form onSubmit={this.handelData.bind(this)}>
        <input type="radio" name="sex" value="male" defaultChecked />mail
        <input type="radio" name="sex" value="femail" />femial
      </form>
    );
  }
}
//3.select
class App extends React.Component {
  handelData() {
    alert(`data :${this.selectValue.value}`);
  }
  render() {
    return (
      <form onSubmit={this.handelData.bind(this)}>
        <select
          defaultValue={"japan"}
          ref={select => (this.selectValue = select)}
        >
          <option value="china">china</option>
          <option value="india">india</option>
          <option value="japan">japan</option>
        </select>
        <input type="submit" value="submit"/>
      </form>
    );
  }
}

6.2受控组建 - 将表单元素:<input><select><textarea>的值以及更新状态保存在组件state状态中,并且只能通过setState方法,进行更新

//1.input:text/textarea
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: "name"
    };
  }
  changeValue(event) {
    this.setState({value: event.target.value});
  }

  handelData() {
    alert(`data :${this.state.value}`);
  }
  render() {
    return (
      <form onSubmit={this.handelData.bind(this)}>
        <input
          type="text"
          value={this.state.value}
          onChange={this.changeValue.bind(this)}
        />
        <input type="submit" value="submit" />
      </form>
    );
  }
}

设置表单元素的value属性之后,其显示值将由this.state.value决定,以满足React状态的同一数据理念。每次键盘敲击之后会执行handleChange方法以更新React状态,显示值也将随着用户的输入改变。
由于 value 属性设置在我们的表单元素上,显示的值总是 this.state.value,以满足 state 状态的同一数据理念。由于 handleChange 在每次敲击键盘时运行,以更新 React state(状态),显示的值将更新为用户的输入。

//2.select
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: "japan"
    };
  }
  changeValue(event) {
    this.setState({value: event.target.value});
  }

  handelData() {
    alert(`data :${this.state.value}`);
  }
  render() {
    return (
      <form onSubmit={this.handelData.bind(this)}>
       <select value={this.state.value} onChange={this.changeValue.bind(this)}>
        <option value="china">china</option>
        <option value="japan">japan</option>
        <option value="india">india</option>
       </select>
        <input type="submit" value="submit" />
      </form>
    );
  }
}

1.在react中,不在单独的给每一个option标签添加selected属性,而是给select标签添加value属性,表示选中的元素
2.处理多个输入元素
当您需要处理多个受控的 input 元素时,您可以为每个元素添加一个 name 属性,并且让处理函数根据 event.target.name 的值来选择要做什么。


七、

七、优化性能

使用react - 最大限度减少更新UI带来的DOM操作数量,那如何更进一步的加快react应用
1.使用react开发者工具

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值