reactJs 基础

时间:2022-01-19 17:40:38

react不是一个完整的mvc,mvvm框架。

react跟web components 不冲突  背景原理:基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新

react的特点就是‘轻’

组件化的开发思路

应用场景:复杂场景下的高性能  重用组件库,组件组合

ReactDOM.render()是React最基本方法 ,用于将模版转为HTML语言,并插入指定的DOM节点。

React.createClass()方法 就用于生成一个组件类  每个组件类都必须有自己的 render: 方法,用于输出组件。

注意:1 组件类第一个字母大写  2 组件类只能包含一个顶层标签 如用<div> 包裹

<HelloMessage name="John"> 组建的属性可以在 组件类的 this.props 对象上获取,this.props.name可以获取到

this.props.children 表示此组件的所有子节点  三种结果:1 没有子节点 undefined 2 有一个子节点 object   3 有多个子节点 array

React.Children.map() 遍历子节点

组件类的PropTypes 属性,用来验证组件实例的属性是否符合要求

        propTypes:{title:React.PropTypes.string.isRequired,}

getDefaultProps 方法用来设置组件属性的默认值  getDefaultProps:function(){return{title:'Hello World'};}

ref属性  可以从组件中获取真实DOM节点   父组件引用子组件

    this.refs.[name] 返回真实的DOM节点 需要等到click事件后调用

var MyComponent = React.createClass({
handleClick:function(){
this.refs.myTextInput.focus();
},
render:function(){
return(
<div>
<input type="text" ref=”myTextInput“ />
<input type = "button" value="Focus the text input" onClick = {this.handleClick} />
)
}
})

组件中getInitialState 方法用于定义初始化状态(对象),可以通过this.state属性读取。

var Input = React.createClass({
getInitialState: function() {
return {value: 'Hello!'};
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
render: function () {
var value = this.state.value;
return (
<div>
<input type="text" value={value} onChange={this.handleChange} />
<p>{value}</p>
</div>
);
}
});

this.setState方法就修改状态值,每次修改后 自动调用this.render 方法,再次渲染组件。

this.props 表示那些一旦定义 就不再改变的特性;

this.state 是会随着用户互动而产生改变的

上面代码中,文本输入框的值,不能用 this.props.value 读取,而要定义一个 onChange事件的回调函数,通过 event.target.value 读取用户输入的值。textarea 元素、select元素、radio元素都属于这种情况

引入解析jsx的文件  <script src='http://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/JSXTransformer.js'></script>  type=''text/javascript"

reactComponent 是指创建的dom节点

react component lifecycle的生命周期:

1 Mounted --- React.renderComponent()    React Components被render解析生成对应的DOM节点 并被插入浏览器的DOM结构的一个过程

componentWillMount 前被调用 --> render --> componentDidMount  后被调用

getDefaultProps()

getInitialState() 初始化

2 Update --- setState() / setProps() 至render()   一个mounted的ReactComponents被重新render的过程

componentWillUpdate / componentDidUpdate   / shouldComponentUpdate /componentWillReceiveProps

3 Unmounted --- React.unmountAndReleaseReactRootNode()  一个mounted的React Components对应的DOM节点 被从DOM结构中移除的这样一个过程

componentWillUnmount

总结:每一个状态 react都封装了对应的hock函数

组件的生命周期:初始化——运行中——销毁

初始化:可使用的钩子

1  getDefaultProps  只调用一次,实例之间共享引用

2 getInitialState  初始化每个实例特有的状态,都需要调用

3  componentWillMount  render之前最后一次修改状态

4 render  只能访问this.props和this.state  不允许修改状态和DOM输出

5 componentDidMount  渲染完成之后触发,可对dom进行操作。

运行中:

1 componentWillReceiveProps 父组件修改属性触发,可以修改新属性,修改状态

2 shouldComponentUpdate  返回faulse 会阻止render调用

3 componentWillUpdate  不能修改属性和状态

4 render 只能访问this.props 和 this.state,不允许修改状态和DOM输出

5 componentDidUpdate 可以修改DOM

销毁:

componentWillUnmount

属性 组件自己不能修改属性,可以从父组件获取属性,父组件也可以修改它的属性,他也可以修改子组件的属性 :本身具有的,属性的四种用方式:

1  <HelloWorld name=? />  出入键值对  "字符创"  “item”

2 {“time”}{123}数字、字符串、等  var props={one:'123',two:321} <HeeloWorld{...props}/>   {...props}展开对象的方式,取到的是值;{props}此方法取到的是对象

3 {【1,2,3】}数组

4 {变量}

状态 只和自己相关 与父组件子组件都不相关,有自己维护 :事物所处的状况,不断变化的

状态用法:

1 getInitialState:初始化每个实例特有的状态

2  setState:更新组件状态

setState-----diff-----dom

区分:组件在运行中需要修改的数据就是 状态。

极客react

非dom节点:

1、 dangerouslySetInnerHTML = {rawHTML}

var rawHTML = {__html:"<h1>i'm inner HTML"}
React.render(<div style={style} dangerouslySetInnerHTML={rawHTML}></div>, )

2、ref

3、key  列表类相同的节点 li 一定要加上key值 <li key='1'></li><li key='2'></li>

事件用法:组件(1,React自有方法:render  、componentWillUpdate、componentDidMount

2. 用户定义方法:handleClick、handleChange、handleMouseover)

绑定事件处理函数:

触摸:onTouchCancel

onTouchEnd

onTouchMove

onTouchStart

键盘:onKeyDown

onKeyPress

onKeyUp

剪切:onCopy

onCut

onPaste

表单:onChange

onInput

onSubmit

焦点:onFocus

onBlur

UI元素:onScroll

滚动:onWheel

鼠标:onDrop/onDrag/onDragEnd/onDragEnter/onDragExit/onDragLeave/onDragOver/onDragStart

onClick/onContextMenu/onDoubleClick/onMouseDown/onMouseEnter/onMouseLeave/onMouseLeave/onMouseMove/onMouseOut/onMouseOver/onMouseUp

事件对象的属性:

reactJs 基础reactJs 基础reactJs 基础reactJs 基础

reactJs 基础reactJs 基础

事件和状态关联:

handleChange:function(e){this.setState({inputText:e.target.value})}

组件协同:

1 组件嵌套: 父子关系  父组件-属性-》子组件;子组件-委托(触发事件)-》父组件

2 mixin:React双向绑定Minxin

组件要可控:符合react的数据流;数据存储在state中,便于使用;

表单元素:

<label htmlFor="name">对应相应的input的id</label>

<input><textarea><select><option></option></select>

事件处理函数复用:

1、bind复用:

handleChange:function(name,event){....}

  {this.handleChange.bind(this,'input')}

2、name复用:

  handleChange:function(event){var name=event.target.name}

  {this.handleChange}

React性能调优:

提高性能的方式:虚拟DOM,diff算法,将dom操作减少到最小,但是

        问题1:父组件更新默认出发所有子组件更新;解决方法:子组件覆盖shouldComponentUpdate方法,返回true,触发更新流程,生成新的虚拟DOM节点与之前的进行比较,不同则进行操作;返回false,自行解决是否更新。

        问题2:列表类型的组件默认更新方式比较复杂;解决方法:给列表中的组件添加key属性

性能调优:分析性能热点

控制台输入React.addons.Perf.start()--->进行一次操作---->React.addons.Perf.stop()  ;完成后台记录消耗时间

      查看记录结果:React.addons.Perf.printInclusive();

如何解决性能问题:1;PureRenderMixin判断是否需要进入更新流程,本质上就是判断状态和属性是否改变(只能处理原始值,不能处理对象)

  在shouldComponentUpdate(nextProps,nextStates)内判断!shallowEqual(this.props,nextProps)||!shallowEqual(this.state,nextState);

2;不可变插件Immutability Helpers,实现js不可变对象

  基本语法:update(obj,cmd)

reactJs 基础

组件嵌套:

reactJs 基础

钩子函数:

初始化:getDefaultProps  只调用一次

getInitialState

componentWillMount  渲染之前最后一次修改状态this.setState({}),触发render()函数;

render

componentDidMount  操作或修改真正的dom

运行中:componentWillReceiveProps  父组件修改属性之前触发,此函数可以修改新属性、修改状态

shouldComponentUpdate  返回false,根据需要使用

componentWillUpdate :不能修改属性和状态

render:只能访问this.props和this.state,不能修改

componentDidUpdate :可以修改dom

销毁:componentwillUnmount  在删除组件之前进行清理操作,比如计时器和事件监听器,必须手动清理。方法1.在子组件中componentwillUnmount:function(){}  方法2:在子组件的handle函数中,调用:React.unmountComponentAtNode(document.getElementsByTagName('body')[0]);//传入的必须是装载入的节点。

React.findDOMNode()

react添加css动画:

var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; 引入react-addons-t

调用:return(<ReactCSSTransitionGroup transitionName="example">{items}</ReactCSSTransitionGroup>)

react添加js动画:

componentDidUpdate:function(){if(this.props.position){setTimeout(this.resolveSetTimeout,this.props.timeoutMs);}},

render:function(){var divStyle={marginLeft:this.state.position};return <div style={divStyle}>this will animate!</div>}})

React.render(<Positioner></positioner>,document.body);

React.render(<Positioner position={100} timeout={10}></Positioner>,document.body);第二次调用,改变属性值props,触发componentDIdUpdate();从而达到动画效果

项目实战:

 1.分析目标-确定开发顺序:页面上有组件->组件能正常显示内容->内容的样式正确->设置项可以正常工作->交互功能正常

在jsx中使用循环,一般会用到Array.prototype.map

class Hello extends React.Component{
render(){
const arr = ['a','b','c'];
return (
<div>
{arr.map((item,index) => {
return <p key={index}> this is {item}</p>
})}
</div>
)
}
}

参考链接:http://www.imooc.com/article/14500

代码分离

page层  ./app/containers/Hello/index.jsx

subpage层  ./app/containers/Hello/subpage/...jsx

component层  ./app/components/...  把多个页面都可能用到的功能,封装到一个组件中,放到此目录下。

数据传递&数据变化

props:一般只用作父组件给子组件传递数据用,不能被自身修改。

每个页面引用Header时,设置独自的title属性值,<Header title='Hello页面'/>;而在子组件中这样取到 render(){return(<p>{this.props.title}</p>)}

state:自身组件状态发生变化,constructor(props,context){super(props,context);this.state = {now:Date.now()}}  render(){return (<div><p>hello world {this.state.now}</p></div>)}}

智能组件&木偶组件

智能组件:./app/containers   简称“页面”,只对数据负责,只需获取数据、定义好数据操作的相关函数,然后将这些数据、函数直接传递给具体的实现组件。

木偶组件:做一些展示的工作,展示给用户。 ./app/components/...

性能检测优化:参考https://github.com/wangfupeng1988/react-simple-o2o-demo/tree/getready-redux-width-react   本地切换到对应的分支

1安装react的性能检测工具npm install react-addons-perf --save  在./app/index.jsx中import Perf from 'react-addons-perf'   if(__DEV__){window.Perf = Perf}

使用:Perf.start()开始检测,Perf.stop停止检测,Perf.printWasted()即可打印出浪费性能的组件列表。

2安装react的优化插件 PureRenderMixin,npm install react-addons-pure-render-mixin --save

使用:在constructor(props,context){super(props,context);this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);}}  重写组件shouldComponentUpdate函数,在每次更新之前判断props和state,如果有变化返回true。

3 Immutable.js优化:使用此来处理数据,实现js中不可变数据的概念。适用于数据结构层次很深(obj.x.y.a.b=10)其定义了新的语法,不轻易使用。

React-router

安装 npm install react-route --save

1 创建子页面./app/containers/App.jsx 所有页面的外壳 ./app/containers/Home等主页、列表页、详情页

2 配置router 创建./app/router/routerMap.jsx 文件

class RouteMap extends React.Component{
updateHandle(){
//每次router变化之后都会触发

render(){
return (
<Router history={this.props.history} onUpdate={this.updateHandle.bind(this)}>
<Route path='./' component={App}>
<IndexRoute component={Home}/>
<Route path='list' component={list}/>
<Route path='detail/:id' component={Detail}/> //id表示参数
<Route path="*" component={NotFound}/>
</Route> //route可以嵌套
</Route>
)
}
}

3 使用Route

./app/index.jsx

import React from 'react'
import {render} from 'react-dom'
import {hashHistory} from 'react-router' import RouteMap from './router/routeMap' render(
<RouteMap history={hashHistory}/>, //hashHistory规定hash来表示router localhost:8080/#/list
document.getElementById('root')
)

页面跳转

1 <link to='/list'>to list </link>

2 js跳转

return(<ul>

      {arr.map((item,index) => {

        return <li key={index} onClick={this.clickHandle.bind(this,item)}>js jump to {item} </li>})}

    </ul>)}

clickHandle(value){

  hashHistory.push('/detail/' + value)

}}

性能优化--静态资源懒加载  huge-apps 

他将react-router本身和webpack的require.ensure结合起来,解决此问题。