React
react历史
- Vue2014年开源
- 2013年面向开发者不是开源的
- angular2009年
- vue双向数据绑定->双向数据流
- react单向数据流
- 内存的改变影响页面的改变不管页面的改变,影响内存的改变,自己处理页面的改变,影响内存,通过事件
- 没有指令
import和require
- import属于加载前置的机制,因此将其全放再代码顶部,代码解析逐个import获取一个引入的列表,先引入依赖,再向下执行代码,加载前置
- require
- if(true) { let querystring=require(’ querystring’); }
- 加载滞后,代码执行到哪一行才进行加载
脚手架
- 下载脚手架工具 npm i -g create-react-app
- 使用
- create-react-app 项目名options 构建项目解构
- cd项目目录&& npm i安装依赖包
- 运行
- npm run start启动
- npm run build生成dist
jsx语法
js+ xml
基本操作总结
- 1:引入React对象
- 2:引入ReactDOM对象
- 3:操作jsx
- jsx不能用+=来运算(不是字符串)
- jsx可以通过数组来输出数据1,2
- const arr = [1,2]
- 4:渲染到指定的元素上
- reactDOM. render (,document . getE lementById(‘app’);
- 5:启动npm run dev
官方推荐的class方式
- 儿子class ->子类构造器中必须super(父类构造器
编写App渲染内容
- 只能有一个根节点函数
调用的示例
- this指向
react中有变化的属性
- className
- htmlFor
传递参数及DOM
- react中之 直接给属性就是数据,在子组件中this.props.属性名获取
- 直接往子组件中扔DOM就是传入的DOM,在自组件中使用this.props.children输出
- 更加健壮的排除空节点undefined或者单节点Object或多子节点Array
- React. Children. map(this . props . children, child=>{ })
获取DOM元素
生命周期
constructor( )
1 constructor (props)
react的构造器是在装载之前被调用的,当构造器实现了React.Component类,你应该在任意的生命之前调用super(props)
- Otherwise, this.props will be undefined in the constructor, which can lead to bugs.
常见的构造函数内目的:
- Initializing local state by assigning an object to this .state .
- Binding event handler methods to an instance.
constructor (props) {
super(props);
// Don't ca11 this .setState() here!
this.state = { counter: 0 };
this.handTeClick = this.hand1eClick.bind(this);//改变handleClick的this的上下文
componentWillMount
官方不推荐在此处发请求,原因可能会造成渲染的阻塞,而将请求放在componentDidMount(数据已经装载,据网上流传会引起二次render)
render ()
在一个class或者function组件中必须需要的
Note
render() will not be invoked if shoul dComponentUpdate( returns false.
componentDidMount( )
1 componentDidMount ()
实际应用发网络请求
组件安装后立即调用componentDidMount () (插入到树中) 。需要DOM节点的初始化应该到这里。如果您需要从远程端点加载数据,那么这是实例化网络请求的好地方
这个方法是建立任何订阅的好地方。如果您这样做,请不要忘记在componentWillUnmount ()中取消订阅。
componentDidupdate()
1 componentDidUpdate (prevProps, prevstate, snapshot)
componentDi dupdate() is invoked immediately after updating occurs. This method is not called for theinitial render.
当组件被更新时,将此作为在DOM.上操作的机会。这也是一一个进行网络请求的好地方,只要您将当前的props与以前的props进行比较(例如,如果props没有改变, 网络请求可能就不需要了)。
componentDidUpdate (prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID) ;
}
}
注意:
componentDidupdate() will not be invoked if shouldComponentupdate() returns false.
shouldComponentUpdate()
componentWillUpdate()
componentWillUnmount()
传值及slot
- 属性约束及默认值
import PropTypes from 'prop-types' ;
static propTypes = {
name :PropTypes.number //string.isRequired
}
static defaultProps = {
name: 'abc'
}
- 传值
import React, {Component} from 'react';
import Son from "./son.js";
class App extends Component{
constructor(){
super();
this.state = {
age:12,
}
}
render() {
let {age} = this.state;
let header = (<div>header</div>);
let footer = (<div>footer</div>)
return (
<div>
我是app组件,一下使用son组件
<hr/>
{/*组件的使用必须首字母大写*/}
{/*<Son age={this.state.age} name="jack"/>*/}
<Son age={age} name="jack" head={header} foot={footer}>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</Son>
</div>
)
}
}
export default App;
import React, {Component} from 'react';
import PropTypes from 'prop-types';
class Son extends Component{
//属性的约定和默认值
static propType = {
text: PropTypes.number // string.isRequired
}
static defaultProps = {
text :'abc',
}
constructor(props){
super(props);
}
render() {
console.log(this.props)
//声明一rage, name属性,this. props中的同名属性进行赋值
let {age, name, head, text} = this.props;
//改变age与this. props. age无关
// 声明一 个引用类型属性,this. props中同名属性的地址进行赋值
//Let{obj}= this. props;
//改变obj.xxx 与this. props.obj.xxx有关
return (
<div>
我是子组件,数据如下:
<hr/>
{/*{this.props}*/}
{name}, {age}
<div style={{backgroundColor:'red'}}>
{head}
</div>
{this.props.children}
<div style={{backgroundColor:'blue'}}>
{this.props.foot}
</div>
{text}
</div>
)
}
}
export default Son;
内置便捷函数
- this.props.children有可能有三种数据结构: 对象/数组/undefined
- React.Children.map (children, function[(thisArg)]) // 返回数组
- 更加健壮的排除空节点undlefined或者null的情况
- React.Children.forEach (children, function [(thisArg)]) //遍历
template补充
-
保证一个跟节点
-
解决方案
-
在react16以后, 可以支持编写[]
-
render(){ return [
1
,2
] } -
render(){ return <React.Fragment> <h1>1</h1> <h1>2</h1> </React.Fragment> }
-
该方式不会创建对于的元素
-
react15和16的区别
React.createClass和 extends Component的区别主要在于:
- 语法区别
- propType 和 getDefaultProps
- 状态的区别
- this区别
- Mixins 混合的区别
语法区别
React.createClass
import React from ' react ' ;
const Contacts = React.createClass({
render() {
return (
<div></div>
);
}
});
export default Contacts ;
React.Component
import React from react' ;
class Contacts extends React.Component {
constructor (props) {
super (props);
}
render() {
return (
<div></div>
);
}
}
后一种方法使用ES6的语法,用constructor构造器来构造默认的属性和状态。
propType和getDefaultProps
React.createClass:通过proTypes对象和getDefaultprops ()方法来设置和获取props.
import React from ' react ' ;
const Contacts = React.createClass ({
propTypes: {
name: React.PropTypes.string},
getDefaultProps() {
return {
name:'abc'
};
},
render() {
return (
<div></div>
);
}
});
export default Contacts ;
React.Component:通过设置两个属性propTypes和defaultProps
import React form 'react' ;
class TodoItem extends React.Component{
static propTypes = { // as static property
name: React.PropTypes.string
};
static defaultProps = { // as static property
name : 1!
};
constructor (props){
super (props)
}
render(){
return <div></div>
}
}
状态的区别
React.createClass:通过getInitialstate()方法返回一个包含初始值的对象
import React from 'react ' ;
let TodoItem = React. createClass({// return an object
getInitialState(){
return {
isEditing: false I
}
},
render(){
return <div></div>
}
})
React.Component:通过constructor设置初始状态
import React from 'react' ;
class TodoItem extends React . Component{
constructor (props){
super(props) ;
this.state = { // define this.state in constructor
isEditing: false
}
}
render(){
return <div></div>
}
}
this区别
React.createClass:会正确绑定this
import React from' react' ;
const Contacts = React.createClass({
handleClick() {
console.1og(this); // React Component instance
},
render() {
return (
<div onClick={this . hand1eclick}></div>//会切换到正确的this上下文
);
}
});
export default Contacts ;
React.Component:由于使用了ES6,这里会有些微不同,属性并不会自动绑定到React类的实例上。
import React from 'react ' ;
class TodoItem extends React.Component{
constructor(props){
super(props);
}
handleClick(){
console.1og(this); // null
}
hand1eFocus(){ // manually bind this
console.1og(this); // React Component Instance
}
hand7eBlur: ()=>{ // use arrow function
console.1og(this); // React Component Ins tance
}
render(){
return <input onClick={this.handleclick}
onFocus={this.handleFocus.bind(this)}
onB7ur={this.hamp1eB1ur}/>
}
}
我们还可以在constructor中来改变this.handleClick执行的上下文,这应该是相对上面一种来说更好的办法,万一我们需要改变语法结构,这种方式完全不需要去改动JSX的部分:
import React from 'react' ;
c1ass Contacts extends React.Component {
constructor(props) {
super (props);
this .hand1eClick = this.handleClick.bind(this);
}
handleClick() {
console.1og(this); // React Component instance
}
render() {
return (
<div onClick={this . handleClick}></div>
);
}
}
export default Contacts;
Mixins
如果我们使用ES6的方式来创建组件,那么React mixins的特性将不能被使用了。
React.createClass:
import React from 'react';
1et MyMixin = {
doSomething(){}
}
1et TodoItem = React.createClass({
mixins: [MyMixin], // add mixin
render(){
return <div></div>
}
})
使用React.createClass的话,我们可以在创建组件时添加一个叫做mixins 的属性,并将可供混合的类的集合以数组的形式赋给mixins。
React.Compoent
export default function (Son) {
return class wrap extends Component {
compomentDidMount () {
conso1e.1og('aaaaa') ;
console.1og()
}
render() {
<Son/>
}
}
}
插件相关
基本使用
- react-router-dom(在浏览器使用)
- react-router-native(开发手机原生应用使用的)。推荐使用react-navigation
使用流程
- 下载npm i react-router-dom ;
- 引入对象,按需引|入,HashRouter, BrowserRouter ,Route
- HashRouter代表路由框架的坑
- BrowserRouter代表路由的坑,最终 是没有#的方式,原理基于click + history.pushState
- Route 代表锚点及组件和填入的位置
Switch选择-个
- 横线匹配一个
- 被其包裹的Route从上到下,只会匹配一个(选其一 )
exact精确匹配
React-router 默认是模糊匹配,所以需要添加exact来适配精确匹配
- 纵向(深入匹配)一个
- 精确匹配锚点(只会匹配一个)
- 应用场景:首页’/’ 需要使用,因为/范围太大,会匹配很多东西
- 其他路由不适用,为了能使用嵌套路由(不要控制纵向(深入)只匹配一个)
默认重定向(相当于404)
- 放在路由最后一位,用来处理页面找不到,配合Switch
- Redirect,常用to属性
NavLink类似router-link
- NavLink 按需引入import {NavLink} from ‘react-router-dom’ ;
- 当做组件来使用,其中属性to(路径与Route中的path匹配
<NavLink to="/index/course" activeSty1e={{ co1or: '#4dc060' }}>样式</NavLink>
<NavLink to=" /index/mine" activeClassName="selected">类名</NavLink>
代码注意
- 主体组件App只能有一个根节点
- 主体坑(HashRouter)也只能有一 个根节点
- NavLink 只能在主体坑中
- Switch中不能有Navllink
路由参数
<Route path= '/user/:data' component= {UserPage}></Route>1
使用
var data = {id:3,name:sam,age:36};
data = JSON.stringify(data);
var path = '/user/${data}';
1.<Link to={path}>用户</Link>
2. hashHistory.push(path);
获取数据:
var data = JSON.parse(this.props.params.data) ;
var {id,name,age} = data;12
通过这种方式跳转到UserPage页面时只能通过传递字符串来传递参数,那么是否有其他方法来优雅地直接传递对象而不仅仅是字符串呢?
二.query
query方式使用很简单,类似于表单中的get方法,传递参数为明文:首先定义路由:
<Route path='/user' component={UserPage}></Route>1
使用
var data = {id:3,name:sam,age:36};
var path = {
pathname:'/user',
search:'?id=4', #url拼接
query:data, # 跳转后附带是参数
}
<Link to={path}>用户</L ink>xxxHistory.push(path);
获取数据:
var data = this.props.location.query;
var {id ,name ,age} = data;
query方式可以传递任意类型的值,但是页面的URL也是由query的值拼接的,URL很长,那么有没有办法类似于表单post方式传递数据使得传递的数据不以明文传输呢?
三. state
state方式类似于post方式,使用方式和query类似,首先定义路由:
<Route path= ' /user' component={Us erPage}></Route>1
使用:
var data = {id:3,name: 'sam' ,age:36} ;
var path = {
pathname:'/user' ,
state :data,
}
<Link to={path}>用户</Link>
hashHistory.push(path) ;
获取数据:
var data = this.props.1ocation.state ;
var {id,name,age} = data;
编程导航
- this.props.history.push
- 改变锚点值,引发页面变更
- 前进或后退this. props . history . goBack() IIgoForward();
- 前进或后退,根据参数
- 通过历史记录来操作导航
嵌套路由
- 在部分相同布局的情况下,局部发生变化
- 避免相同布局的重复渲染
- 在需要出现嵌套路由的组件位置中,直接写上坑、path、 组件
- 嵌套的子路由的path必须写成完成的路径