1. React数据流
React数据流是自上向下单向流动,即父组件到子组件。
state与props是react组件中重要的概念。如果顶层组件初始化props,那么react会向下遍历整棵组件树,重新尝试渲染搜索相关的子组件。而state只关心每个组件自己内部的状态,这些状态只能在组件内部改变。
把组件看成一个函数,那么它接受了props作为参数,内部由state作为函数的内部参数,返回一个Virtual DOM的实现。
state
在react没有结合redux框架前,它自身也同样可以管理组件的内部状态,这类状态统一称为state。
当组件内部使用库内置的setState方法时,该组件会尝试重新渲染。我们可以这样理解,因为我们改变了内部状态,组件需要更新。
import React,{Component} from 'react' class Counter extends Component { constructor(props) { supre(props) this.state = { count: 0 } } handleClick(e) { e.preventDefault() this.setState({ count: this.state.count + 1 }) } render() { return ( <div> <p>{this.state.count}</p> <button onClick={this.handleClick.bind(this)}></button> </div> ) } }
在react中常常在事件处理方法中更新state,如上述计数器。这样就可以把组件内状态封装在实现中。
setState是一个异步方法,一个生命周期内所有的setState方法会合并操作。
props
props是react用来让组件之间互相联系的一种机制。react的单向数据流,主要的流动管道就是props。props本身是不可变的。当我们试图修改props的原始值时,react会报出类型错误的警告。如下,我们在constructor中修改了props的值。
react为props同样提供了默认配置,通过defaultProps静态变量的方式来定义。当组件被调用的时候,默认值保证渲染后始终有值。
子组件props
在react中有一个重要且内置的prop--children,它代表组件的子组件集合。children可以根据传入子组件的数量来决定是否是数组类型。this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array。
React.Children是react官方提供的一系列操作children的方法。它提供map,forEach,count等函数,可以为我们处理子组件提供便利。
用function props与父组件通信
可以通过props传递函数给子组件,通过子组件调用和父组件进行信息交互。
propTypes
propTypes用户桂法props的类型与必须的状态。如果组件定义了propTypes,那么在开发环境下,就会对组件的props值得类型做检查,如果传入的props不能与之匹配,React会在控制台进行warning。
2. React生命周期
react组件的生命周期可以根据广义定义描述,可以分为挂载,渲染和卸载这几个阶段。当渲染后的组件需要更新时,我们会重新渲染组件,直至卸载。
生命周期可以分为两种: 1. 当组件在挂载或卸载的时候; 2. 当组件接收新的数据时,即组件更新时。
挂载和卸载过程
1. 组件的挂载
组件的挂载是最基本的过程,这个过程主要做组件状态的初始化:
import React,{ Component,PropTypes } from 'react'; class App extends Component { static propTypes = {} static defaultProps = {} constructor(props) { supre(props) this.state = {} } componentWillMount() {} componentDidMount() {} render() { return () } }
我们可以看到propTypes和defaulProps分别代表props类型检查和默认类型。这两个属性被声明成静态属性,意味着从类外面可以对它们进行访问,例如:App.propTypes和App.defaultProps。
这里可以看到两个明显的声明周期方法。componentWillMount会在render方法之前执行,componentDidMount方法会在render方法之后执行,分别代表渲染前后的时刻。
这里没有什么特别的地方,包括读取初始state和props以及两个组件生命周期方法componentWillMount和componentDidMount,这些都只会在组件初始化时运行一次。
如果我们在componentWillMount中执行setState方法,这样是没有意义的。因为此时组件还没有渲染完毕,调用setState组件会更新state,但组件只会渲染一次。
如果我们在componentDidMount中执行setState,组件会再次更新,不过初始化过程中就渲染了两次组件。
组件的卸载
组件的卸载很简单,只有componentWillUnmount这一个卸载前状态:
import React,{Component} from 'react' class App extends Component { componentWillUnmount() { } render() { return () } }
在componentWillUnMount方法中,我们常常会执行一些清理方法。
数据更新过程
更新过程指的是父组件向下传递props或者组件自身执行setState方法时发生的一系列更新动作。
import React,PropTypes } from 'react'; class App extends Component { componentWillReceiveProps(nextProps) { this.setState({}) } shouldComponentUpdate(nextProps,nextState) { return true } componentWillUpdate(nextProps,nextState) { } componentDidUpdate(prevProps,prevState) { } render() { return () } }
如果组件自身的state更新了,那么会一次执行shouldComponentUpdate,componentWillUpdate,render,componentDidUpdate。
shouldComponentUpdate它接受需要更新的props和state,让开发者增加必要的条件判断,在需要的时候更新,不需要的时候不更新。
默认情况下,当props改变的时候,react会渲染所有子节点,因为shouldComponentUpdate默认返回true。
componentWillUpdate和componentDidUpdata这两个生命周期方法很容易理解,它们代表更新过程中渲染前后的时刻。此时,我们可以想到componentWillUpdate方法提供需要更新的props和state,而componentDidUpdate提供更新前的props和state。
注意:不能在componentWillUpdate中执行setState。
如果组件是由父组件更新props而更新的,那么在shouldComponentUpdate之前会执行componentWillReceiveProps方法。此方法可以作为在传入props之后,渲染之前setState的机会。
3. React与DOM
现在我们讨论下如何将组件渲染到真实的DOM上。
ReactDOM
ReactDOM中的API比较少,只有findDOMNode,unmountComponentAtNode和render。
- findDOMNode
在React中只有在componentDidMount和componentDidUpdate方法中可以获取到真正的DOM元素。React提供获取DOM元素的方法有两种,其中一种就是findDOMNode:
DOMElement findDOMNode(ReactComponent component)
当组件被渲染到DOM中后,findDOMNode返回该React组件实例相应的DOM节点。它可以用于获取表单的value以及用于DOM的测量。
import React from 'react' import ReactDOM from 'react-dom' class App extends Component { componentDidMount() { const dom = ReactDOM.findDOMNode(this) } render() { return () } }
如果在render中返回null,那么findDOMNode也返回null。findDOMNode只对以及挂载的组件有效。
- render
要把react渲染的虚拟DOM渲染到浏览器的DOM当中,就要使用render方法了。
ReactComponent render( ReactElement element,DOMElement container,[function callback] )
该方法把元素挂载到container中,并返回element的实例子(即refs引用)。如果是无状态组件,render会返回null,当组件安装完毕,callback就会被调用。
当组件在初次渲染之后再次更新时,react不会把整个组件重新渲染一次,而会用它高效的DOM diff算法做局部的更新。
- ReactDOM的不稳定方法
这里没怎么看,感觉用处不大就不介绍了。
- refs
刚才我们描述了ReactDOM的render方法,比如我们渲染App组件到root节点下:
const myAppInstance=ReactDOM.render(<App/>,document.getElementById('root')); myAppInstance.doSth();
我们利用render方法获取了App组件的实力,然后我们可以对它做一些操作。但是在组件内JSX不会返回一个组件的实例,它是一个ReactElement,只是告诉react被挂载的组件应该长什么样子:
cosnt MyApp = <App />
refs是react组件中非常特殊的props,可以附件到任何组件上,字面意思理解就是reference,组件被调用时会新建一个该组件的实例。
它也可以是一个回调函数,这个回调函数会在组件被挂载后立即执行:
import React,{ Component } from 'react'; class App extends Component { constructor(props){ super(props); this.handleClick = this.handleClick.bind(this); } handleClick() { if (this.myTextInput !== null) { this.myTextInput.focus(); } render() { return ( <div> <input type="text" ref={(ref) => this.myTextInput = ref} /> <input type="button" value="Focus the text input" onClick={this.handleClick} /> </div> ); } }
在这个例子,我们得到了input组件的真正实例,所以可以在按钮被按下后调用输入框focus方法。该例子把refs放到原生的DOM组件input中,我们可以通过refs得到DOM节点;如果把refs放到React组件,比如:<TextInput>,我们获得的就是TextInput的实例,因此就可以调用TextInput的实例方法。
refs同样支持字符串,对于DOM操作,不仅可以使用findDOMNode获得该组件DOM,还可以使用refs获得组件内部的DOM。
import React,{ Component } from 'react' import ReactDOM from 'react-dom' class App extends Component { componentDidMount() { // myComp 是 Comp 的一个实例,因此需要用 findDOMNode 转换为相应的 DOM const myComp = this.refs.myComp; const dom = findDOMNode(myComp); } render() { return ( <div> <Comp ref="myComp" /> </div> ); } }
要获取一个react组件的引用,既可以使用this来获取当前react组件,也可以使用refs来获取你拥有的子组件的引用。
原文链接:https://www.f2er.com/react/302153.html