react的知识总结

ES6 创建组件:

import React from 'react';	react核心包会是吧jsx语句。
class 组件名 extends React.Component{
		constrctor(props){ 组件有状态 constrctor就出现
			super(props) 类如果有继承 super就要出现
			需要在组件构造器内处理传递过来的props时,props参数就出现
			this.实例属性=值
			this.state={ 本地状态}
		}
		render(){
			return jsx=>jsx是js的一种数据类型,在UI模板里写js语句,要有{}}
		方法1(){} 自定义的方法
		方法2(){}
	}

问题1:实例属性和本地状态有什么区别呢? 普通实例属性不响应式,也就是数据发生改变,但是视图层并不会发生改变。

组件属性(props):

调用组件:<组件名 属性名=值 属性名2=2 .. />	传递属性
	组件内部: {this.props.属性名}   jsx表达式  使用属性
			  this 代表的是组件本身

	值类型:字符||{表达式}
	this.props.属性名==array 需要循环
	arr值:this.props.属性名.map(function(){
		return html
	})
	json {json} 报错, 对象无法直接通过{obj}展示->{obj.key}

组件之间数据传递(props传递)

	父到子	props 传递 <Child 属性={父数据} />
	子到父   props 传递 <Child 属性={父方法} />
			{this.props.属性.bind(this,子数据)}
	中间人: 子a传父传子b
	订阅发布库: pubsub-js
	**所有 React 组件都必须是纯函数,并禁止修改其自身 props**
	思想:
	组件拆分目标:为了复用
	组件如何拆:单一原则
	状态应该给谁:
		尽量给顶层组件(状态提升)->props->子组件
		可以从 props(属性) 或者 state(状态) 得到,那么它可不在 state(状态) 中
		方法-》操作数据(数据|状态在哪,方法就应该在哪)
	props取名:从组件本身的角度来命名, 而不是它被使用的上下文环境
	纯函数:不会试图改变它们的输入,并且对于同样的输入,始终可以得到相同的结果。
	React组件都必须是纯函数,并禁止修改其自身 props
		function(a,b){不会随机,不会修改a和b的值,输出可控}
	

函数式组件(无状态|UI|纯函数):

	无状态(没有state)组件(简写)创建:
		function 组件名(props){}
		const 组件名=(props)=>(jsx)
		const 组件名=props=>jsx
		const 组件名=(props)=>{
			let xx=props.xx
			return html
		}

	无状态组件特点:
		不能访问this对象(this.ref,this.state  ... )
		只能访问props
		无需实例化,渲染性能高
		this.方法/钩子(生命周期)  也不需要

props类型检查

	需要安装  import propsTypes from 'prop-types'

	默认值:		组件.defaultProps={propName:}
	类型约定:	组件.propTypes={propsName:使用propsTypes库.类型名}

		propsTypes库.类型名
		propName: propsTypes.array/bool/func/number/object/string
	必传参数: propName: propsTypes库.类型名.isRequired
	App.defaultProps={
		title:'标题'
	};
	App.propTypes={
	  	title:proptypes.string,
	  	num:proptypes.number.isRequired//必传props
	};

解决setState是异步拿不到更新后的数据问题

setState: 会将多个 setState() 调用合并为一次更新,获取不到更新后的数据。
所以不能同步依赖上一个setState的值,作为下一个setState的参数
		解决:
			1) this.setState(function(prevState,props){})
			  prevState 抓取之前this.setState的所有状态
			  props 所有属性
		      更新会被合并,浅合并。
		    2) 函数节流(异步操作)
		    3) ev.target......
1、函数节流(异步操作)
changeIpt(ev) {
    this.setState({ipt: ev.target.value});//修改后的结果是异步的
    setTimeout(() => {
      fetchJsonp(
        // 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+ev.target.value,
        'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+this.state.ipt,
        {
          jsonpCallback:'cb'
        }
      ).then(
        res=>res.json()
      ).then(
        data=>this.setState({list:data.s})
      )
    }, 0)

2、this.setState(function(prevState,props){})prevState 抓取之前this.setState的所有状态
    this.setState({ipt: ev.target.value});//修改后的结果是异步的
    this.setState(function (prevState) {
      // prevState==修改后的this.state
      // return {ipt: prevState.ipt}
      fetchJsonp(
        // 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+ev.target.value,
        'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+prevState.ipt,
        {
          jsonpCallback:'cb'
        }
      ).then(
        res=>res.json()
      ).then(
        data=>this.setState({list:data.s})
      )
    });
  }

组件的状态 (state|数据|封装状态|本地状态|初始数据)

	constructor(){		es6
		this.state={}
	}

	获取: this.state.实例属性
	修改: this.setState({实例属性:})

	事件:驼峰命名  es6 事件函数内部this会丢失
	<元素 onClick={this.实例方法}
	修正this的指向
	1) onClick={this.实例方法.bind(this,)}
	2) onClick={()=>{this.实例方法()}}
	3) 构造器: this.实例方法=this.实例方法.bind(this)
	   实例方法(ev)	ev 代理事件对象 ev.target 返回虚拟dom √

refs获取真实DOM

	获取jsx元素  获取的是真实dom
		给jsx元素 设置ref属性=名字
		组件内部: this.refs.名字
	何时用:
		处理focus、文本选择或者媒体播放
		触发强制动画
		集成第三方DOM库

受控元素:

	react 默认是单项绑定  defaultValue
	value={this.state.数据名}  model->view
	onChange={this.监听方法}   view->model(  setState )
	监听方法: this.setState(...)
处理多个输入元素
	可以为每个元素添加一个 name 属性(通常和数据名一致)
	处理函数根据 ev.target.name 的值来选择要做什么

name="inputUserName" name="inputContent"
this.setState({[ev.target.name]:ev.target.value})

react 处理 样式:

	1) 在index.html : 引入  link/style  场景:应用的公共样式
	2)在组件里面引入: import './css/xx.css'  是全局 注入口(程序) 公共样式
		问题: 选择器冲突,
		解决:
			a) 命名空间 √
			b) 模块化:
				引入 import 变量  from './css/xx.css' 模块
				使用 <jsx className={变量.类名}
				配置 改名xx.css -> xx.module.css 需要模块化的才修改,不影响其他非模块化css写法 √
				原理:	webpack配置 "style-loader!css-loader?modules" | modules:true
	jsx:
		className="类名 类名2" className={返回字符}
		style={{key:value,key:value}}

动画

css tansition
	CSSTransition/CSSTransitionGroup 官网推荐
	ant.desinge动画  √

		https://motion.ant.design/api/queue-anim
		**QueueAnim:进退场动画  组件
		QueueAnim组件内部的 一级元素&& 进退场,做动画
		一级元素要有key,根据编号依次做动画,无key不动画
		包裹路由组件无效(一级元素&& 进退场);因为路由组件并没有消失,所以要包裹路由组件具体包裹的哪个组件里面才行。**

生命周期流程

实例化 ->  更新期  -> 销毁时
	实例化:
		es5:
			1.取得默认属性(getDefaultProps) 外部传入的props
			2.初始状态(getInitailState)  state状态
		    3.即将挂载 componentWillMount
		    4.描画VDOM  render
		    5.挂载完毕 componentDidMount
		es6:
			1.取得默认属性(getDefaultProps) 外部传入的props
			2.初始状态(getInitailState)  state状态
				1 && 2 都在构造器里面完成
				constructor(props){
					super(props) == getDefaultProps
					this.state={} == getInitailState
				}
		    3.即将挂载 componentWillMount
		    4.描画DOM  render
		    5.挂载完毕 componentDidMount
	更新期:
		0.props改变 componentWillReceiveProps(nextProps)
		初始化render时不执行,这里调用更新状态(改变状态)是安全的,并不会触发额外的	render调用。nextProps 更新后  this.props更新前
		1.是否更新 shouldComponentUpdate  ;
		指视图,函数返回一个布尔值来确定是否要更新视图层。默认为true表示会更	新视图层。是一个性能优化的钩子。
		2.即将更新 componentWillUpdate
		3.描画Vdom  render
		4.描画结束 componentDidUpdate
	销毁时:
		即将卸载 componentWillUnmount
		可以做一些组件相关的清理工作,例如取消计时器、网络请求等

数据交互

官方脚手架 静态数据读取时,参考根指向public  '/data' == public/data
	fetch	原生就有
	fetch(url+数据,{配置}).then(成功函数(res)).catch(error)
	res.ok -> true/false 成功/失败
	res.status - > 状态码
	res.body 数据 数据流(stream)
	res.text() 转换 文本(string)
		过程异步:	return res.text()
		同步: res.text().then((data)=>{})	data:转换后的数据
	res.json() 转  对象
	配置:
		method:'POST'
		headers:{"Content-type":"application/x-www-form-urlencoded"},
		body:'a=1&b=2'	|	{a:1,b:2}	|	URLSearchParams

jsonp:  fetch不带jsonp请求  需要依赖第三库
	npm install fetch-jsonp -D
	import xxx from 'xxx'
	用法:
		fetchJsonp(url+数据,{配置}).then(success(res)).catch(error)
		特点: 是个promise 返回promise 数据是个流
		解析:res.json()  -> 流转换数据 是异步
		配置:
			timeout: 延时  5000
			jsonpCallback: 回调函数key 		callback
			jsonpCallbackFunction: null 回调函数名


react路由 4.x

资料:API:https://reacttraining.com/react-router/web/guides/quick-start
CN:http://blog.csdn.net/sinat_17775997/article/details/77411324
redux:https://github.com/reacttraining/reactrouter/tree/master/packages/react-router-redux
区别:
V4
嵌套式路由(路由配置在组件内部),动态路由,包容性(多路由渲染)
舍去了路由钩子
V3(vue)
分离式(统一位置配置),静态路由,排他性(只有一个路由被渲染)
理念:
遵循Just Component的 API 设计理念 万物皆组件,路由规则位于布局和 UI 本身之间

	安装引入 react-router-dom
	React Router被拆分成三个包:react-router,react-router-dom和react-router-native。react-router提供核心的路由组件与函数。其余两个则提供运行环境(即浏览器与react-native)所需的特定组件

	BrowserRouter 使用 HTML5 提供的 history API 来保持 UI 和 URL 的同步
	HashRouter 使用 URL 的 hash (例如:window.location.hash) 来保持 UI 和URL 的同步

	结构:
		BrowserRouter|HashRouter 路由对象
			route
				根组件(App)|其他组件
					NavLink|Link  导航
					Route    匹配+展示
					Redirect 跳转
					404 <Redirect to="/error"/>
					默认路由 <Route exact path={match.path} render={fuc}
	Route 属性
		path(string): 路由匹配路径。(没有path属性的Route 总是会 匹配);
		exact(bool):
			为true时,要求全路径|严格匹配(/home)。V4 的路由默认为“包含|模糊”的(//home都匹配),这意味着多个 <Route> 可以同时进行匹配和渲染

		component:在地址匹配的时候React的组件才会被渲染,route props也会随着一起被渲染
		render:这种方式对于内联渲染和包装组件却不引起意料之外的重新挂载特别方便
	Link:
		to:string/object:要跳转的路径或地址;
	NavLink:是<Link> 的一个特定版本
		activeClassName(string):设置选中样式,默认值为 active;
		activeStyle(object):当元素被选中时, 为此元素添加样式;
	Switch:该组件用来渲染匹配地址的第一个<Route>或者<Redirect>,仅渲染一个路由,排他性路由,默认全匹配(场景:侧边栏和面包屑,引导选项卡等)
	Redirect:
		<Redirect from='/' to='/home'/> 总是会被重定向
	404:	<Route component={Error}/> 总是会匹配

	参数数据:{history,location,match}==props
		传递:
			to={match.url+'/001'}
			to={`${match.url}/002?a=1&b=2`}
			to={{pathname:match.url+'/003',search:'?a=11&b=12',hash:'#a1'}}
			<Route path={match.path+'/:aid'} component={Detail}
				注意:
					url - (浏览器 URL 中的实际路径) URL 匹配的部分。 用于构建嵌套的 <Link>
					path - (路由编写的路径) 用于匹配路径模式。用于构建嵌套的 <Route>
		接收:
			接参数:{match.params.aid}
			接数据:{location.search}
			接地址:{location.pathname}
		注意:
			无法从v4 中获取 URL 的查询字符串了。因为没有关于如何处理复杂查询字符串的标准。所以,作者让开发者去选择如何处理查询字符串。推荐query-string库
	跳转:
		history.push('/user?a=1&b=2')
		history.push({pathname:'/user',search:'?a=11&b=22'})
		history.replace({pathname:'/user',search:'?a=111&b=222'})
		history.go(-1)

	授权路由:自定义路由
		前置守卫
			<AuthRoute path="/user" component={User}/>
			AuthRoute==授权路由==react组件==自定义路由
			条件:返回一个Route 组件
				  Route的render函数内部判断加载目标||Redirect组件
			实现:
				AuthRoute = ({ component: Component, ...rest }) => (
				  <Route {...rest} render={props =>
				      Math.random()<0.5 ?
				        <Component {...props} />
				       : <Redirect to="/login" />
				    }
				  />
				)
			目标组件	Component == User
			延展剩余属性 rest
			路由信息 ...props User组件需要用到的路由信息
		运用:数据预载
			AuthRoute 组件构造器存状态和预载数据
			DidMount钩子里异步请求,获取状态和数据
				fetch(url).then(result=>this.setState({}))
			render钩子返回 Route
				 <Route {...rest} render={props => Xxx?<Component data={预载数据}
				 if(!this.state.hasAuthed) return null;初始渲染时,未发送认证请求,因此不渲染
	Prompt:后置守卫,离开后守卫
		import { Prompt } from 'react-router-dom'
		<Prompt
          when={this.state.isBlocking}
          message={location=>{return `未保存,是否去向${location.pathname}`}}
        />
        message: 后面可以跟简单的提示语,也可以跟函数,函数是有默认参数的。
        when: when的属性值为true时防止跳转;
例子:
class Auth extends React.Component{
  constructor(props){
    super();
    this.state={
      hasAuth:false,//是否发送请求
      auth:false,
      data:{}
    }
  }
  componentDidMount(){
    fetch(
      `/data/user.json`
    ).then(
      res=>res.json()
    ).then(
      resData=>this.setState({auth:resData.auth,data:resData.data,hasAuth:true})
    )
  }
  render(){
    if (!this.state.hasAuth) return null;
    let {component:Component, ...rest}=this.props;
    return (
      <Route {...rest} render={(contents)=>(
        this.state.auth ?
          <Component userdata={this.state.data} {...contents} /> :
          <Redirect to="/login" />
      )} />
    )
  }
}

export default Auth;

状态管理

	flux(思想) vue实现(vuex) react实现(react-redux)

状态管理(redux):可以同一个地方查询状态,改变状态,传播状态
思维:
	在顶层组件创建store(状态),其他底层组件共享这个store(状态)
数据流动:
	component->action->reducer->state->component
	component: 展示结果(含处理结果代码)
	action: 动作转发,异步请求,
	reducer: 业务处理逻辑,返回(return)新state
	state:	状态收集,更新内部state状态,更新订阅(store.subscribe)state的组件(component)

	通过store.dispatch发送action 给 reducer
	在组件内部 通过 store.getState() 抓state状态  特点 只抓一次
			   store.subscribe() 订阅  数据更新,会触发
			   getState放在subscribe内部
操作流程:
	1. {createStore} from 'redux'
	2. 生成默认state defaultState={}
	3.	创建reducer
		const reducer = (state=defaultState,action)=>{
			let {type,payload}=action
			swtich type
				case XXXXX
				更新copy后的state  Object.assign(,,)
			default:
				return state
		}
	4. 创建store对象
		store = createStore(reducer,defaultState)

	5. store传递给组件
		<组件名 store={store}/>

	6. 更新,状态获取
		组件内部:	this.props.store== store
			this.props.store.dispatch({type:xxx,payload:ooo}) 发送action给reducer
			this.props.store.subscribe(回调)  订阅 state  更新state时触发
			this.props.store.getState() 获取状态,执行一次
react-redux
	基于redux思想,专门为react而生

思想:  容器组件, UI组件
	App: 拿到store,修改、获取store
	store:外面
index.js:
	import {Provider,connect} from react-redux

	<Provider store={store}>
		<容器组件/>
	</Provider>
异步action + 可复用:	dispatch(asyncAction(xx,xx,xx))  dispatch 接受对象  asyncAtion内部要返回对象
异步action + 可复用:	dispatch(asyncAction)  dispatch 不接受函数  
	需要中间件redux-thunk支持 ,dispatch默认支持对象,不接受函数,中间件用来改装dispatch
	let store = createStore(
	  reducer,
	  state,
	  applyMiddleware(thunk)  applyMiddleware是redux API
	);
异步action 数据回传给调用方
	asyncAction = (url,type,id) => (dispatch,getState)=>{dispatch1次 + return fetch + then + dispatch2次 + return data}

	https://blog.csdn.net/yuanyuanispeak/article/details/78842963
	C:\Users\user\Desktop\react\actions-redux-thunk-promise.js

片段(fragments)

	为一个组件返回多个元素。 可以让你将子元素列表添加到一个分组中,并且不会在DOM中增加额外节点
	<React.Fragment key="bmw"></..>

高阶组件

	是一个函数能够接受一个组件并返回一个新的组件。
	组件是将props转化成UI,然而高阶组件将一个组价转化成另外一个组件
	例如Redux的connect

子路由使用父路由的展示区(插槽)

	<Route path="/a" render={()=>
    		<div>
    			<Switch>
    				<Route path="/a/b" component={b}
    				<Route path="/a/c" component={c}
    				<Route path="/a" component={a}
    			</Switch>
    		</div>
    	>

单页滚动条问题

	react 单页滚动条问题
		路由切换,每次切换到页面顶部 app.js
		componentWillReceiveProps(nextProps){//props改变时
		    if(this.props.location !== nextProps.location){//当前地址不等于目标地址
		      window.scrollTo(0,0);//滚动到顶部
		    }
		  }

		页面切换出去再切换回来后怎样保持之前的滚动位置
			componentDidMount->window.scrollTo(0,sTop)
			componentWillUnmount->sTop = document.documentElement.scrollTop
			sTop =  模块内部变量 | 类属性
		参考:https://blog.csdn.net/tujiaw/article/details/77511460
		
		判断某个组件是否滚动到底部
		https://blog.csdn.net/tujiaw/article/details/77511460
		react-scroller

		参考:
			https://www.cnblogs.com/yuan-luo/p/9041124.html
			https://blog.csdn.net/tujiaw/article/details/77511460
			https://segmentfault.com/q/1010000010619676

异步路由|组件

异步组件:create-react-app 环境 webpack自动分片打包
	原理 import ("./ChildB.js").then(
        	ChildB=>console.log(ChildB)
      	)

    方式1 const Child = asyncComponent(()=>import("./Child"))

    	export default function asyncComponent(importComponent) {
		  class AsyncComponent extends Component {
		    constructor(props) {
		      super(props);

		      this.state = {
		        component: null
		      };
		    }
		    async componentDidMount() {
		      const { default: component } = await importComponent();

		      this.setState({
		        component: component
		      });
		      
		    }

		    render() {
		      const C = this.state.component;
		      return C ? <C {...this.props} /> : null;
		    }
		  }

		  return AsyncComponent;
		}
	方式2 
	  import Loadable from 'react-loadable';
	  const Loading = () => <div>Loading...</div>;
	  const Home = Loadable({
	  	loader: () => import('./routes/Home'),
	 	loading: Loading,
	 	loading:()=>{return null}
	  });

	  路由 <Route path=.. component={Home}/>  路由懒加载

同级组件传值思路

a)	子A->->子B
		父方法(){this.refs..方法}
	b) pub/sub模式 消息通知(观察者模式)  npm install pubsub-js -D
		订阅:	token=pubsub.subscribe('消息名',回调函数('消息名',数据))
		发布:  pubsub.publish('消息名',数据)
		清除指定订阅:pubsub.unsubscribe(token|'消息名'|回调函数名);
		清除所有:pubsub.unsubscribeAll()

		注意:订阅方不存在了,相关的订阅注意清除   	

路由监听

	componentWillReceiveProps(nextProps){
		nextProps.location.pathname
	}

猜你喜欢

转载自blog.csdn.net/Miss_hhl/article/details/103657940