React Native开发之必备React基础

为了帮助你们快速上手React Native开发,在这本节中将向你们介绍开发React Native所须要的一些React必备基础知识javascript

概述

本节课将从React的特色、如何使用React、JSX语法,而后会对组件(Component)以及组件的属性(props)、状态(state)、生命周期等方面进行讲解。html

经过本节课程能学到什么?

  • 对React有个全面的认识;
  • 熟悉JSX基本语法;
  • 了解组件结构;
  • 熟悉组件的生命周期;
  • 学会使用props;
  • 学会使用state;
  • 熟悉自定义组件;

React是什么?

React 是 Facebook 推出的开源 JavaScript Library,它是一个用于组建用户界面的JavaScript库,让你以更简单的方式来建立交互式用户界面,它的出现让许多革新性的 Web 观念开始流行起来,例如:Virtual DOM、Component,声明式渲染等。java

声明式与命令式node

命令式编程:命令“机器”如何去作事情(how),这样无论你想要的是什么(what),它都会按照你的命令实现。
声明式编程:告诉“机器”你想要的是什么(what),让机器想出如何去作(how)。
复制代码

演示react

  1. 当数据改变时,React将高效的更新和渲染须要更新的组件。声明式视图使你的代码更可预测,更容易调试。
  2. 构建封装管理本身的状态的组件,而后将它们组装成复杂的用户界面。因为组件逻辑是用JavaScript编写的,而不是模板,因此你能够轻松地经过您的应用程序传递丰富的数据,并保持DOM状态。
  3. 一次学习随处可写,学习React,你不只能够将它用于Web开发,也能够用于React Native来开发Android和iOS应用。

如何使用?

构建一个新的 React 单页应用,能够经过Create React App来完成。它能够帮助你配置开发环境,以便你可使用最新的 JavaScript 特性,还能提供一个友好的开发体验,并为生产环境优化你的应用。git

npm install -g create-react-app
create-react-app my-app
cd my-app
npm start
复制代码
"dependencies": {
    "react": "^16.6.3",//是 React 的核心库
    "react-dom": "^16.6.3",//提供与 DOM 相关的功能
    "react-scripts": "2.1.1"//create-react-app 的一个核心包,一些脚本和工具的默认配置都集成在里面
  },
复制代码

ReactDOM.render

ReactDOM.render(element, container[, callback])github

渲染一个 React 元素到由 container 提供的 DOM 中,而且返回组件的一个 引用(reference) (或者对于 无状态组件 返回 null )。算法

JSX

JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。 每个XML标签都会被JSX转换工具转换成纯JavaScript代码,使用JSX,组件的结构和组件之间的关系看上去更加清晰。 JSX并非React必须使用的,但React官方建议咱们使用 JSX , 由于它能定义简洁且咱们熟知的包含属性的树状结构语法。npm

Usage:编程

React.render(//使用JSX
    <div>
        <div>
            <div>content</div>
        </div>
    </div>,
    document.getElementById('example')
);
React.render(//不使用JSX
    React.createElement('div', null,
        React.createElement('div', null,
            React.createElement('div', null, 'content')
        )
    ),
    document.getElementById('example')
);
复制代码

createElement

React.createElement(
  type,
  [props],
  [...children]
)
复制代码

根据给定的类型建立并返回新的 React element 。参数type既能够是一个html标签名称字符串(例如'div' 或 'span' ),也能够是一个 React component 类型(一个类或一个函数)。

React.createElement(Hello, {toWhat: 'World'}, 'hello'),
//等价于 <Hello toWhat="World">hello</Hello>,

复制代码

HTML标签 与 React组件 对比

React 能够渲染 HTML 标签 (strings) 或 React 组件 (classes)。 要渲染 HTML 标签,只需在 JSX 里使用小写字母开头的标签名。

var myDivElement = <div className="foo" />;
React.render(myDivElement, document.root);
复制代码

要渲染 React 组件,只需建立一个大写字母开头的本地变量。

var MyComponent = ...;
var myElement = <MyComponent someProperty={true} />;
React.render(myElement, document.body);
复制代码

提示:

  • React 的 JSX 里约定分别使用首字母大、小写来区分本地组件的类和 HTML 标签。
  • 因为 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议做为 XML 属性名。做为替代, React DOM 使用 className 和 htmlFor 来作对应的属性。

JavaScript 表达式

属性表达式

要使用 JavaScript 表达式做为属性值,只需把这个表达式用一对大括号 {} 包起来,不要用引号 ""

// 输入 (JSX):
var person = <Person name={window.isLoggedIn ? window.name : ''} />;
// 输出 (JS):
var person = React.createElement(
  Person,
  {name: window.isLoggedIn ? window.name : ''}
);
复制代码

子节点表达式

一样地,JavaScript 表达式可用于描述子结点:

// 输入 (JSX):
var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
// 输出 (JS):
var content = React.createElement(
  Container,
  null,
  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
);
复制代码

注释

JSX 里添加注释很容易,它们只是 JS 表达式而已。你只须要在一个标签的子节点内(非最外层)用 {} 包围要注释的部分。

class ReactDemo extends Component {
  render() {
    return (
      <View style={styles.container}>
        {/*标签子节点的注释*/}
        <Text style={styles.welcome} //textAlign='right' textShadowColor='yellow' /*color='red' textShadowRadius='1'*/ >
          React Native!
        </Text>
      </View>
    );
  }
}
复制代码

心得:在标签节点之外注释,和一般的注释是同样的,多行用“/**/” 单行用“//”;

JSX延展属性

不要试图去修改组件的属性

不推荐作法:

var component = <Component />;
  component.props.foo = x; // 不推荐
  component.props.bar = y; // 不推荐
复制代码

这样修改组件的属性,会致使React不会对组件的属性类型(propTypes)进行的检查。从而引起一些预料以外的问题。

推荐作法:

var component = <Component foo={x} bar={y} />;
复制代码

延展属性(Spread Attributes)

你可使用 JSX 的新特性 - 延展属性:

var props = {};
  props.foo = x;
  props.bar = y;
  var component = <Component {...props} />;
复制代码

传入对象的属性会被复制到组件内。

它能被屡次使用,也能够和其它属性一块儿用。注意顺序很重要,后面的会覆盖掉前面的。

var props = { foo: 'default' };
  var component = <Component {...props} foo={'override'} />;
  console.log(component.props.foo); // 'override'
复制代码

上文出现的...标记被叫作延展操做符(spread operator)已经被 ES6 数组 支持。

www.devio.org/2018/09/09/…

Component

React 容许将代码封装成组件(component),而后像插入普通 HTML 标签同样,在网页中插入这个组件。

class Hello extends React.Component{
    render() {
        return <h1>Hello {this.props.name}</h1>;
    }
}
ReactDOM.render(
  <Hello name="John" />,
  document.getElementById('example')
);
复制代码

上面代码中,变量 HelloMessage 就是一个组件类。模板插入 <HelloMessage />时,会自动生成 HelloMessage 的一个实例。全部组件类都必须有本身的 render 方法,用于输出组件。

注意

  • 组件类的第一个字母必须大写
  • 组件类只能包含一个顶层标签? 演示

组件的属性(props)

咱们能够经过this.props.xx的形式获取组件对象的属性,对象的属性能够任意定义,但要避免与JavaScript关键字冲突。

遍历对象的属性:

this.props.children会返回组件对象的全部属性。 React 提供一个工具方法 React.Children 来处理 this.props.children 。咱们能够用 React.Children.mapReact.Children.forEach 来遍历子节点。

React.Children.map

React.Children.map(children, function[(thisArg)])
复制代码

在包含在 children 里的每一个子级上调用函数,调用的函数的 this 设置为 thisArg 。若是 children 是一个嵌套的对象或数组,它将被遍历。若是 children 是 null 或 undefined ,返回 null 或 undefined 而不是一个空数组。

React.Children.forEach

React.Children.forEach(children, function[(thisArg)])
复制代码

Usage:

class NotesList extends React.Component{
    render(){
        return (
            <ol> { React.Children.map(this.props.children,(child)=> { return <h1>{child}</h1>; }) } </ol>
        );
    }
}
ReactDOM.render(<NotesList> <span>hello</span> <span>world</span> </NotesList>, document.getElementById('root'));
复制代码

演示

[PropTypes]

组件的属性能够接受任意值,字符串、对象、函数等等均可以。有时,咱们须要一种机制,验证别人使用组件时,提供的参数是否符合要求。 组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求。

React.PropTypes 从 React v15.5开始被移入了prop-types,使用时须要留意;

import  PropTypes from 'prop-types'
class MyTitle extends React.Component{
    static propTypes={
        title: PropTypes.string.isRequired,
    };
    render() {
        return <h1> title:{this.props.title} </h1>;
    }
}
ReactDOM.render(<MyTitle />, document.getElementById('root'));
复制代码

上面的Mytitle组件有一个title属性。PropTypes 告诉 React,这个 title 属性是必须的,并且它的值必须是字符串。如今,咱们设置 title 属性的值是一个数值。

var data = 123;
ReactDOM.render(
  <MyTitle title={data} />,
  document.body
);
复制代码

这样一来,title属性就通不过验证了。控制台会显示一行错误信息。

Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.

更多的PropTypes设置,能够查看官方文档

默认属性

此外,能够经过defaultProps用来设置组件属性的默认值。

class MyTitle extends React.Component{
    static defaultProps={
        shortName:'MyTitle'
    };
    render() {
        return <h1> {this.props.shortName}</h1>;
    }
}
ReactDOM.render(<MyTitle/>, document.getElementById('root'));
复制代码

上面代码会输出"MyTitle"

ref 属性(获取真实的DOM节点)

组件并非真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫作虚拟 DOM (virtual DOM)。只有当它插入文档之后,才会变成真实的 DOM 。根据 React 的设计,全部的 DOM 变更,都先在虚拟 DOM 上发生,而后再将实际发生变更的部分,反映在真实 DOM上,这种算法叫作 DOM diff ,它能够极大提升网页的性能表现。

可是,有时须要从组件获取真实 DOM 的节点,这时就要用到 ref 属性。

class Alert extends React.Component {
    showAlert(message) {
        alert(`Debug:${message}`);
    }

    render() {
        return null;
    }
}

class MyTitle extends React.Component {
    onClick = () => {
        this.refs.alert.showAlert('MyTitle');
    };

    render() {
        return <div>
            <h1 onClick={this.onClick}>Click me</h1>
            <Alert ref='alert'/>
        </div>;
    }
}

ReactDOM.render(<MyTitle/>, document.getElementById('root'));
复制代码

上面代码中,组件 MyTitle 的子节点有一个Alert组件,为了调用这个组件提供的方法,这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了作到这一点,咱们在使用这个组件的时候必须为其设置一个ref属性,而后 this.refs.[refName] 就会返回这个真实的 DOM 节点。

须要注意的是,因为 this.refs.[refName] 属性获取的是真实 DOM ,因此必须等到虚拟 DOM 插入文档之后,才能使用这个属性,不然会报错。上面代码中,经过为组件指定 Click 事件的回调函数,确保了只有等到真实 DOM 发生 Click 事件以后,才会读取 this.refs.[refName] 属性。

React 组件支持不少事件,除了 Click 事件之外,还有 KeyDown 、Copy、Scroll 等,完整的事件清单请查看官方文档

心得:ref属性在开发中使用频率很高,使用它你能够获取到任何你想要获取的组件的对象,有了这个对象你就能够灵活地作不少事情,好比:读写对象的变量,甚至调用对象的函数。

state

上文讲到了props,组件会根据props的变化来进行渲染,但组件没法改变自身的props,那么组件为了实现交互,可使用组件的 state 。state 是组件私有的,能够经过state={}方式初始化,经过调用 this.setState() 来改变它。当 state 更新以后,组件就会从新渲染本身。

render() 方法依赖于 this.props 和 this.state ,框架会确保渲染出来的 UI 界面老是与输入( this.props 和 this.state )保持一致。

初始化state

能够经过一下两种方式来初始化state,在组件的生命周期中仅执行一次,用于设置组件的初始化 state 。

constructor(props){
    super(props);
    this.state={
        name:''
    }
}
//or
state={
    name:''
}
复制代码

更新 state

经过this.setState()方法来更新state,调用该方法后,React会从新渲染相关的UI。 this.setState({favorite:!this.state.favorite});

Usage:

class FavoriteButton extends React.Component{
   state={
       favorite:false
   };
    handleClick=()=>{
        this.setState({favorite:!this.state.favorite});
    };
    render(){
        const text=this.state.favorite? 'favorite':'un favorite';
        return (
            <h1 onClick={this.handleClick}> You {text} this. Click to toggle. </h1>
        );
    }
}
复制代码

上面代码是一个 FavoriteButton 组件,它的经过 state={}初始状态,也就是一个对象,这个对象能够经过 this.state 属性读取。当用户点击组件,致使状态变化,this.setState 方法就修改状态值,每次修改之后,自动调用 this.render 方法,再次渲染组件。

心得:因为 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些本组件没法改变的特性,而 this.state 是会随着用户互动而产生变化的特性。

组件的生命周期

在iOS中UIViewController提供了(void)viewWillAppear:(BOOL)animated, - (void)viewDidLoad,(void)viewWillDisappear:(BOOL)animated等生命周期方法,在Android中Activity则提供了onCreate(),onStart(),onResume(),onPause(),onStop(),onDestroy()等生命周期方法,这些生命周期方法描述了一个界面从建立到销毁的一辈子。

那么在React 中组件(Component)也是有本身的生命周期方法的。

react-lifecycle-methods-diagram

演示

[组件的生命周期分红三个时期:

  • Mounting:建立时
  • Updating:更新时
  • Unmounting:卸载时

不安全的方法

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

使用这些生命周期方法一般会致使错误和不一致,所以未来会被弃用。在新的React版本中他们被标记为UNSAFE。

static-lifecycle-methods

Mounting(装载)

constructor()

constructor(props)
复制代码

React组件的构造函数将会在装配以前被调用。当为一个React.Component子类定义构造函数时,你应该在任何其余的表达式以前调用super(props)。不然,this.props在构造函数中将是未定义,并可能引起异常。

构造函数是初始化状态的合适位置。若你不初始化状态且不绑定方法,那你也不须要为你的React组件定义一个构造函数。

static getDerivedStateFromProps()

static getDerivedStateFromProps(nextProps, prevState)
复制代码

组件实例化后和接受新属性时将会调用getDerivedStateFromProps。它应该返回一个对象来更新状态,或者返回null来代表新属性不须要更新任何状态。

注意,若是父组件致使了组件的从新渲染,即便属性没有更新,这一方法也会被调用。若是你只想处理变化,那么能够经过比较新旧值来完成。

调用this.setState() 一般不会触发 getDerivedStateFromProps()。

render

ReactComponent render()
复制代码

render() 方法是必须的。

当被调用时,其会检查this.props 和 this.state并返回如下类型中的一个:

  • React元素。 一般是由 JSX 建立。该元素多是一个原生DOM组件的表示,如
    ,或者是一个你定义的复合组件。
  • 字符串和数字。 这些将被渲染为 DOM 中的 text node。
  • Portals。 由 ReactDOM.createPortal 建立。
  • null。 什么都不渲染。
  • 布尔值。 什么都不渲染。(一般存在于 return test && 写法,其中 test 是布尔值。)

返回null 或 false时,ReactDOM.findDOMNode(this) 将返回 null。

render()函数应该是纯粹的,也就是说该函数不修改组件的 state,每次调用都返回相同的结果,不读写 DOM 信息,也不和浏览器交互(例如经过使用 setTimeout)。若是须要和浏览器交互,在 componentDidMount() 中或者其它生命周期方法中作这件事。保持 render() 纯粹,可使服务器端渲染更加切实可行,也使组件更容易被理解。

提示:若 shouldComponentUpdate()返回false,render()函数将不会被调用。

componentDidMount()

componentDidMount()
复制代码

componentDidMount()在组件被装配后当即调用,一般在该方法中进行一些初始化操做。·初始化时须要DOM节点的操做能够放到这里进行`。若你须要从远端加载数据,这是一个适合实现网络请求的地方。在该方法里设置状态将会触发重渲。

这一方法是一个发起任何订阅的好地方。若是你这么作了,别忘了在componentWillUnmount()退订。

另外,在这个方法中调用setState()将会触发一次额外的渲染,可是它将在浏览器刷新屏幕以前发生。这保证了即便render()将会调用两次,但用户不会看到中间状态。

Updating (更新)

shouldComponentUpdate

shouldComponentUpdate(nextProps, nextState)
复制代码

在接收到新的 props 或者 state,将要渲染以前调用,以让React知道当前状态或属性的改变是否不影响组件的输出。

该方法在初始化渲染的时候不会调用,在使用 forceUpdate 方法的时候也不会。若是肯定新的 props 和 state 不须要从新渲染,则此处应该 返回 false。

心得:重写次方你能够根据实际状况,来灵活的控制组件当 props 和 state 发生变化时是否要从新渲染组件。

getSnapshotBeforeUpdate

getSnapshotBeforeUpdate(prevProps, prevState)
复制代码

getSnapshotBeforeUpdate()在最新的渲染输出提交给DOM前将会当即调用。它让你的组件能在当前的值可能要改变前得到它们。这一辈子命周期返回的任何值将会 做为参数被传递给componentDidUpdate()。

componentDidUpdate

componentDidUpdate(prevProps, prevState, snapshot)
复制代码

在组件的更新已经同步到 DOM 中以后马上被调用。

该方法不会在初始化渲染的时候调用。使用该方法能够在组件更新以后操做 DOM 元素。

Unmounting(移除)

componentWillUnmount

componentWillUnmount()
复制代码

在组件从 DOM 中移除的时候马上被调用。

在该方法中执行任何须要的清理,好比无效的定时器,或者清除在 componentDidMount 中建立的 DOM 元素。

参考

相关文章
相关标签/搜索