React技术栈总结
React部分
基础概念
React是国外FackBook公司在2013年5月开源的一个用于构建用户界面的JavaScript库,它采用了组件化的思想。所谓组件化,就是将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。
React的一个愿景是,把浏览器兼容的问题解决了,让程序员不需要再和浏览器打交道,只需要和一个框架对接就好了。它这里边使用了一个Bable工具,能够将ES6的语法转译成ES5的语法,react-dom中也构建了一个虚拟库,使得代码可以在不同浏览器、不同设备中兼容。
React是单向数据流,只允许数据改变视图,但是它有受控组件,类似于Vue的v-model。
state–>view–>setState–>new view
React认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。
所以,React使用了JSX,但是Reat官方并不强制要求使用 JSX,如果不使用JSX的话,可以用React.createElement来写。但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用,它还可以使 React 显示更多有用的错误和警告消息。
key值的作用是在对比新旧虚拟DOM时作为独一无二的标记。
用索引值作为key,其实是不合适的,如果数据顺序变了,它会认为新旧虚拟DOM的同一索引值元素还存在,但是内容变了,所以又全部重新渲染。最好的key值是数据的id。
函数式组件
Reat的组件形式有类组件和函数式组件,在老版本中使用类组件比较多,但有了hooks之后,函数式组件也可以使用状态,使用副作用,所以,函数式组件就崛起了。
函数式组件的本质是一个常规函数,接受一个参数props并返回一个reactElement。
常用hook:
useState 注意点:setState方法,不会进行对象合并,所以,如果对象里面有多个键值对,需要把其他键值对解构出来;setState方法同样是异步方法,它并不会一执行就马上改变数据。
useEffect 类似于类组件中的生命周期,但其实函数式组件中没有生命周期的定义,它被成为副作用。
useEffect(()=>{组件加载或更新执行
return ()=>{组件卸载后执行}
},[data 监听的state,state改变,执行])
注意点:如果只在组件挂载阶段执行一次,可以将监听数据设为空[]
;
为什么组件卸载后还能执行卸载函数呢?因为React在首次编译的时候把它记下来了。
useRef 只能在函数式组件中使用,它比createRef更强大,createRef也可以在函数式组件中使用。
它有两种用法:1、关联DOM节点,2、保存组件更新前的一些特性,如果useRef()里面放的是组件中的状态(或其他非关联DOM)时,组件更新 ref 中保存值并不会自动更新,需要我们手动更新(refXXX.current=XXX)。
第二个作用A与“在组件外定义一个全局变量存储数据“B的区别:
B的组件卸载后,全局变量还是在的,而且,如果这个组件使用多次,全局变量是公用的,会产生冲突,例子C;而ref是组件内部的,独立的。
例子C:有一个全局变量为global,初始值为true,第一个组件挂载,取反,第二个组件挂载,会在原基础上修改,最终变为true。
自定义hook:react-redux、reat-router等第三方库里面都有自定义hook。
个人错题集
return JSX的时候,因为JS的语法特性,如果return那一行后面没有代码,直接转行了,后面的代码是不会被解析的,比如:
return
<APP/> //这里的APP组件是不会被解析的,除非加小括号
return (
<APP/>
)
当return行后面有代码的时候,又会继续解析下去,比如:
return <NAV/>
<CONTEXT/> //这里的CONTEXT组件也会被解析
Redux
一个JavaScript状态容器,相当于Vuex。但是,Vuex是Vue专用的,而Redux并不是只用于React,它也可以用于其他界面库。
核心概念
我们通常把一个应用中的数据存储到Object Tree中,这个对象我们成为state。
然后呢,为了保证数据状态的可维护和测试,不推荐直接修改state中的原数据。我们通过发起一个action(一个普通JavaScript对象,包含type和payload–‘操作state的同时传入的数据’),来更新state中的数据。
接着呢,为了把action和state串起来,就开发出了reducer这个纯函数。它仅仅是一个接受state和action的纯函数。
最终,为了对state、action、reducer进行统一管理和维护,我们创建了一个store对象。
Redux三大原则
单一数据源
整个应用的state被储存在一颗object tree中,并且这个object tree只存在于唯一一个store中。
State是只读的
唯一改变state的方法就是触发action,action是一个用于描述已发生事件的普通对象。
使用纯函数来执行修改
为了描述action如何改变state tree,你需要编写reducers。
相关概念
官方文档上,Redux提供可预测化的状态管理,其实也是得益于纯函数的特征。
什么是纯函数?它有以下四个特征:
1、相同的输入永远会有相同的输出,相同的action,永远返回相同的state;
2、不直接修改函数的输入值,(它是return一个新的state);
3、不依赖外部环境状态,(比如外部的一些全局变量,reducer是通通不用的,这点使得它利于重构,只需要修改reduer内部就可以了,外部不需要打理);
4、无任务副作用,(实际上也是基于上面3点,它不会受到外部的影响,也不会影响外部的情况)。
比较常用的api有:createStore、getState()、subscribe(listener)、combineReducers(reducers)
React Redux
Redux官方提供的React绑定库。原理:利用了React自身的跨组件通信context。
使用React Redux需要在组件最外层包括一个Provider
<Provider store={传入一个store}>
<APP/>
</Provider>
问题:Router
也需要包裹在组件最外层,怎么操作?
谁包裹谁都可以。Provider
和Router
本身是没有里外层关系的,只要它们都是在组件最外层就可以了。
使用React Redux组件通信的两种方法:
1、connect,它是一个高阶组件。(React的withRouter(APP)就是一个高阶组件)
connect的参数是一个callback,callback接受一个参数,然后合并入组件的props中,所以,组件通过props来获取。
2、通过react-redux的hooks方法。原理:React的自定义hook。3个hooks:
useSelector 用于获取state,代码: const data = useSelector(state=>state.data)
useDispatch 用于获取dispatch,代码: const dispatch = useDispatch()
``useStore 用于获取store,代码: const store = useStore() `
个人错题集
React有一条原则,不能直接修改props,Redux有一条原则,state是只读的,唯一改变state的方法就是触发action。所以,当我们在做数据修改的时候,通常都使用一些不直接修改原数据的方法,比如map、filter。注意:Redux和React只是在渐层监控数据是否被直接修改,foreach在浅层不能够修改原数据,但是深层可以。这是一个漏洞吧,平时写代码的时候最好不用这些方法,因为违背了框架库的设计原理。
React-Router
相关理念和概念
路由:根据不同的URL,给用户展示不同的视图
SPA:单页面应用
页面切换机制:将 JavaScript 与 URL 相结合
前端路由:基于 URL Hash 的路由 和 基于 HTML5 History API 的路由
不同环境下的路由库:WEB+native
基于WEB的组件库:react-router-dom
它有两种路由:基于HTML5 History API的BrowserRouter 基于URL Hash的HashRouter
Route组件:通过该组件来设置单个路由信息,同时,该组件调用的渲染组件,会接收到路由参数。
exact属性:表示该路由使用精确匹配模式,非exact模式下’/‘匹配所有以’/'开头的路由,
注意事项:如果配置的路由,它不是精准匹配exact,那么是获取不到params参数的。
Link组件:类似html中的a标签,但是它拦截了a标签的默认动作,不让页面跳转,然后根据路由模式(history?hash?)来进行处理,改变了URL,同时显示对应的组件。
react的Link标签是怎么做到url改变时页面不刷新的?涉及到底层history的api,有一个pushstate,点击a标签的时候,先阻止默认事件,不让a标签连接,然后通过BOM的api:creatstate修改url。(待完善)
to属性:类似a标签中的href。
render属性:属性值是一个函数,如果需要传递props,必须使用render。
NavLink组件:额外提供了一些属性。
activeStyle:当该NavLink组件被匹配时,激活activeStyle中的样式。
activeClassName:当该NavLink组件被匹配时,对应clas。
isActive:它是一个函数,返回布尔值,通过isActive可以自定义激活逻辑,然后调用上面属性的样式。
Switch组件:和JS的switch方法类似。
Redirect组件:重定向,用于404页面等。
withRouter组件:向非路由绑定组件中注入路由对象,它是一个高阶组件。
hooks:useHistory、useLocation、useParams、useRouteMatch
动态路由:把满足某种规则的路由全部匹配到同一个组件,组件根据URL后面的动态部分,修改数据,渲染视图。