当前位置:

React Native开发:必备React基础

访客 2024-04-22 258 0

为了帮助大家快速上手ReactNative开发,在这本节中将向大家介绍开发ReactNative所需要的一些React必备基础知识。

概述

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

通过本节课程能学到什么?
  • 对React有个全面的认识;
  • 熟悉JSX基本语法;
  • 了解组件结构;
  • 熟悉组件的生命周期;
  • 学会使用props;
  • 学会使用state;
  • 熟悉自定义组件;
React是什么?

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

声明式与命令式

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

演示

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

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

npminstall-gcreate-react-appcreate-react-appmy-appcdmy-appnpmstart"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])

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

JSX

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

Usage:

React.render(//使用JSX<div><div><div>content</div></div></div>,document.getElementById('example'));React.render(//不使用JSXReact.createElement('div',null,React.createElement('div',null,React.createElement('div',null,'content'))),document.getElementById('example'));createElementReact.createElement(type,[props],[...children])

根据给定的类型创建并返回新的Reactelement。参数type既可以是一个html标签名称字符串(例如'div'或'span'),也可以是一个Reactcomponent类型(一个类或一个函数)。

React.createElement(Hello,{toWhat:'World'},'hello'),//等价于<HellotoWhat="World">hello</Hello>,HTML标签与React组件对比

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

varmyDivElement=<divclassName="foo"/>;React.render(myDivElement,document.root);

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

varMyComponent=...;varmyElement=<MyComponentsomeProperty={true}/>;React.render(myElement,document.body);

提示:

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

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

//输入(JSX):varperson=<Personname={window.isLoggedIn?window.name:''}/>;//输出(JS):varperson=React.createElement(Person,{name:window.isLoggedIn?window.name:''});子节点表达式

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

//输入(JSX):varcontent=<Container>{window.isLoggedIn?<Nav/>:<Login/>}</Container>;//输出(JS):varcontent=React.createElement(Container,null,window.isLoggedIn?React.createElement(Nav):React.createElement(Login));注释

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

classReactDemoextendsComponent{render(){return(<Viewstyle={styles.container}>{/*标签子节点的注释*/}<Textstyle={styles.welcome}//textAlign='right'textShadowColor='yellow'/*color='red'textShadowRadius='1'*/>ReactNative!</Text></View>);}}

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

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

不推荐做法:

varcomponent=<Component/>;component.props.foo=x;//不推荐component.props.bar=y;//不推荐

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

推荐做法:

varcomponent=<Componentfoo={x}bar={y}/>;延展属性(SpreadAttributes)

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

varprops={};props.foo=x;props.bar=y;varcomponent=<Component{...props}/>;

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

它能被多次使用,也可以和其它属性一起用。注意顺序很重要,后面的会覆盖掉前面的。

varprops={foo:'default'};varcomponent=<Component{...props}foo={'override'}/>;console.log(component.props.foo);//'override'

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

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

Component

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

classHelloextendsReact.Component{render(){return<h1>Hello{this.props.name}</h1>;}}ReactDOM.render(<Helloname="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:

classNotesListextendsReact.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从Reactv15.5开始被移入了prop-types,使用时需要留意;

importPropTypesfrom'prop-types'classMyTitleextendsReact.Component{staticpropTypes={title:PropTypes.string.isRequired,};render(){return<h1>title:{this.props.title}</h1>;}}ReactDOM.render(<MyTitle/>,document.getElementById('root'));

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

vardata=123;ReactDOM.render(<MyTitletitle={data}/>,document.body);

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

Warning:FailedpropType:Invalidprop`title`oftype`number`suppliedto`MyTitle`,expected`string`.

更多的PropTypes设置,可以查看官方文档。

默认属性

此外,可以通过defaultProps用来设置组件属性的默认值。

classMyTitleextendsReact.Component{staticdefaultProps={shortName:'MyTitle'};render(){return<h1>{this.props.shortName}</h1>;}}ReactDOM.render(<MyTitle/>,document.getElementById('root'));

上面代码会输出"MyTitle"

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

组件并不是真实的DOM节点,而是存在于内存之中的一种数据结构,叫做虚拟DOM(virtualDOM)。只有当它插入文档以后,才会变成真实的DOM。根据React的设计,所有的DOM变动,都先在虚拟DOM上发生,然后再将实际发生变动的部分,反映在真实DOM上,这种算法叫做DOMdiff,它可以极大提高网页的性能表现。

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

classAlertextendsReact.Component{showAlert(message){alert(`Debug:${message}`);}render(){returnnull;}}classMyTitleextendsReact.Component{onClick=()=>{this.refs.alert.showAlert('MyTitle');};render(){return<div><h1onClick={this.onClick}>Clickme</h1><Alertref='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:''}}//orstate={name:''}更新state

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

Usage:

classFavoriteButtonextendsReact.Component{state={favorite:false};handleClick=()=>{this.setState({favorite:!this.state.favorite});};render(){consttext=this.state.favorite?'favorite':'unfavorite';return(<h1onClick={this.handleClick}>You{text}this.Clicktotoggle.</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)也是有自己的生命周期方法的。

演示

[组件的生命周期分成三个时期:
  • Mounting:创建时
  • Updating:更新时
  • Unmounting:卸载时
不安全的方法
  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

使用这些生命周期方法通常会导致错误和不一致,因此将来会被弃用。在新的React版本中他们被标记为UNSAFE。

static-lifecycle-methods

Mounting(装载)
  • constructor();
  • staticgetDerivedStateFromProps()
  • render()
  • componentDidMount()
constructor()constructor(props)

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

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

staticgetDerivedStateFromProps()staticgetDerivedStateFromProps(nextProps,prevState)

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

注意,如果父组件导致了组件的重新渲染,即使属性没有更新,这一方法也会被调用。如果你只想处理变化,那么可以通过比较新旧值来完成。

调用this.setState()通常不会触发getDerivedStateFromProps()。

renderReactComponentrender()

render()方法是必须的。

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

  • React元素。通常是由JSX创建。该元素可能是一个原生DOM组件的表示,如,或者是一个你定义的复合组件。

发表评论

  • 评论列表
还没有人评论,快来抢沙发吧~