react

字数 6796阅读 245

[toc]

REACT

react :
1.用来构建用户界面的 JAVASCRIPT 库
2.react 专注于视图层,通过组件来构建界面应用。

为什么要组件化开发

可复用 可组件 可开发

jsx

javascript xml
自定义标签 HTML也是属于xml
一种javascript 的语法扩展,我们推荐在react中使用JSX来描述用户界面。
<{来区别html和js
创建的是虚拟的DOM元素就是一个JS对象,最终REACT会最终渲染成真正的元素。
js对象:{type:"h1",props:{className:"red"},chileren:"hello"}
1.jsx元素 ->react元素
2.虚拟DOM (js对象)->render转换成真实的DOM

1.jsx=js+html <{ 来区分HTML和js
2.若有多个相邻的Jsx元素,最外层必须有个包围的元素
3.{}是js表达式,变量,三元运算符,不可以放语句,纯对象,可以放数组,但是数组成员不能放对象。
4.{}可以获取返回值得内容,不可放函数本身
5.return 后若有jsx元素,需要换行时,的拿()包起来,表示一起返回,
6.行内样式的放在一个对象里,style={styleObj}

ReactDOM.render(<div style={styleObj}>{bind(obj)}</div>,window.root);

7.特殊属相,与关键词一样的属性,采用驼峰式命名法,与html标签里设置属性一样。

react的组件

组件:函数组件,类组件
组件和jsx的区别:组件名首字母大写
分类:函数组件和类组件
函数组件:没有this,没有状态,通过props接收数据
类组件:有this,有状态,有生命周期。通过state状态,

获取数据有两种方式:props 只能接收,不能修改。在函数和类组件都有
state:只有类组件里面有,改变数据的值。

Object.keys(this.props) :属性转换成数组。还有JSON.stringfiy(this.props) 把纯对象转换成字符串

对props的属性进行验证:安装npm install prop-types

受控组件和非受控组件:

非受控组件:通常说的是表单元素 表单元素的value是根据用户输入的内容确定的
受控组件:value值不再是由用户输入值确定,而是有react的state状态来控制,必须加onChange事件。

//jsonp 和改变响应头的cros的方式解决跨域请求。
那axios里面觉得jsonp不好,就支持cros的跨域方式。
那如果jsonp支持的话就安装 cnpm install jsonp

生命周期钩子函数

组件调用开始:重新调用可能从头开始。
constructor
componentWillMount 组件将要挂载
render:渲染组件
componentDidMount :组件挂载完成
//数据更新前
shouldComponentUpdate(nextProps,nextState) 询问是否要更新组件 return 值为true时,为false时则不更新。
componentWillUpdate 更新前触发
render 渲染组件
componentDidUpdate 更新后触发
组件销毁
componentWillUnmount :
属性更新
componentWillReceiveProps(newProps)
将要接收属性 true false

脚手架

生成脚手架:create-react-app my-app
官方提供的,快速搭建REAVT工程结构的脚手架。
注意点:如果当前电脑安装了yarn,基于脚手架安装工程目录的时候也是基于yarn安装的,我们后期再手动安装其他模块,建议不要使用npm了,因为有时候会发生丢包,包错乱等事项。
1.作用:快速构建一个工程化结构目录

node_modules:安装包
public:index.html,xxx.html 存放项目静态页面的,或者是无需webpack编译,直接在页面中导入的资源文件。
src:index.js,xxx.xx  当前项目大部分的逻辑代码,和一些资源都是存放到这个文件夹下的。
.gitignore:packjage.json  依赖的模块,安装包。

脚手架生成的配置清单

react:16.4的版本
react-dom:16.4版本 构建html
react-native:这是构建app的
react-scripts :1.1版本 把webpack所需要的插件及加载器全部融合一起了,
包括:webpack webpack-dev-server
babel eslint ....
脚手架为了美化结构目录,把配置好的webpack隐藏到react-script中,放到node_modules下。

常见的操作命令

yarn xxx 或者 npm run start

start :开发环境下使用的

  • yarn start
  • 按照生成的webpack配置项,把项目整体进行打包编译,把react的jsx语法编译为es6语法,把css等进行处理。
  • 创建一个本地服务的,端口号默认3000,并且自动打开浏览器预览编译后的代码。
  • 并且自动检测文件的改动。一旦发生改动就会重新编译,然后自动刷新浏览器。

build:生产环境下使用的

  • cnpm run build 或 yarn bulid
  • 生成一个build文件夹,用来存放打包或者文件。
  • 基于默认的webpack配置项,把项目进行编译打包
  • 把build找那个的内容步数到服务器上即可

test:测试模式下,一般不用

eject:

  • yarn eject cnpm run eject
  • 把默认隐藏的webpack配置项暴露出来,这样我们可以在默认的基础上进行修改,变成符合我们自己项目的配置结构。
  • 此操作是不可逆转的,一旦暴露出配置项,将无法再把它隐藏。谨慎操作
  • config 文件夹 :存放的是webpack的一些配置项
    • webpack-config.dev.js 执行yarn start 走的是这个配置项。
    • webpack.config.prod.js 执行yarn build 走的是这个配置项
    • scripts 当我们执行yarn xxx的时候,首先找到这里对应的js文件,并且把它执行,从而走到对应的webpack配置。

修改脚手架

安装less

  • yarn add less less-loader
  • 修改webpack 配置项:

上传的时候都会加上时间戳:js/index.js/?201808041111 get请求。后来有了webpack后,就加hash值,有了hash值处理为了不走缓存的。

修改本地启动服务的端口号
openBrower:打开浏览器的
start.js的43行 ,协议,域名都可以改
$ set PORT=8000 设置环境变量的端口号8000(同样的还有http post)
也可以在package.json里面改:
start:"set PORT=9000&set HTTPS=true&node scripts/start.js";
环境变量只要执行一次。之后不变的了就。

扩展

仔细研究webpack 配置项和每一项的作用
研究webpack的优化,打包编译的时候快一点,把文件压缩更小一些等。

render

render([JSX],[container],[callback]);
第二个虚拟DOM最后渲染到的容器,不建议是BODY,render渲染的时候会用新的DOM覆盖了原有容器中的内容。
第三个虚拟DOM插入到页面中,触发的回调函数 已经成为真实的DOM

jsx的渲染原理

render([JSX],[container],[callback]);
jsx指的是javascript xml(html)
REACT独有的语法=》virtual dom 虚拟DOM。
container:虚拟DOM最后渲染到的容器,不建议是BODY。
callback:把虚拟DOM插入到页面中,触发的回调函数。(现在已经成为真实的DOM)。

原理:1.基于babel-preset-react-app这个语法解析包,把JSX语法元素变为REACT.createElement(...)这种格式;2.基于createElement把传递的参数,处理为jsx对象。react在渲染解析的时候,会把所有的html标签都转换为createelement的处理方式(返回一个元素对象)。具体的有type:标签名;prop:属性对象(给当前元素设置的属性都在这里,没有设置属性结果是null,如果有儿子,则把儿子依次传递过来,没有就啥都不传。style,children

//jsx的渲染原理
//1.基于babel-react-app 这个语法解析包,把jsx语法元素变诶react.createElement(...)这种格式
//2.基于createElement把传递的参数处理为jsx对象,即JS对象。
//createElement():REACT在渲染解析的时候,会把所有的HTML标签都转换为CREATE-ELEMENT的处理方式,(返回一个元素对象)
//->type 标签名 props:属性对象(给当前元素设置的属性都在这里,没有设置属性结果是null)
//如果有儿子,则把儿子一次传递过来,没有就啥也不传。
//返回对象的格式:
//(
// type:'div',
// props:{
// style:...,
// ....
// children:可能有可能没有,有的话可能是一个数组,也可能是一个字符串。或者是一个对象。
// key:null,
// ref:null
// }
// )

//3.基于render把对象按照动态创建DOM元素的方式插入到指定的容器中即可。

http://babeljs.io/ 把所有的语法编译es5
//创建组件的两种办法:
//1,函数式组件创建:执行函数的jsx即可
//2.继承是component类来创建组件,在组件render方法中返回JSX即可

//调取组件:单闭合 双闭合
1.单闭合是用函数式组件创建的,不能写属性,没有children。
2.双闭合是用class extends Component{} 里面有children的属性

//virtual dom 即为虚拟DOM 即 jsx react 独有的语法

react的基础知识

1.属性

调取组件的时候,传递给组件的信息(render渲染的时候会把props传递给组件,props就是属性)
属性的作用:让组件呈现不同的效果,具有多元化。
属性的特点:传递进来的属性在组件内部不能修改,也就是它是“只读”的。(只能重新调取组件,来修改属性的值,并且重新传递值)。
/在jsx中,null,undefined都是表示空元素/
虽然不能修改属性值,但是在类创建组件的方式中,我们给组件栓塞制默认值和一设置一些规则。
yarn add prop-types 安装来改变数值和字符串。的安装包

继承component和PureComponent的区别:
React.PureComponent 与 React.Component 几乎完全相同,但 React.PureComponent 通过prop和state的浅对比来实现 shouldComponentUpate()。

如果React组件的 render() 函数在给定相同的props和state下渲染为相同的结果,在某些场景下你可以使用 React.PureComponent 来提升性能。

React.PureComponent 的 shouldComponentUpdate() 只会对对象进行浅对比。如果对象包含复杂的数据结构,它可能会因深层的数据不一致而产生错误的否定判断(表现为对象深层的数据已改变视图却没有更新, 原文:false-negatives)。当你期望只拥有简单的props和state时,才去继承 PureComponent ,或者在你知道深层的数据结构已经发生改变时使用 forceUpate() 。或者,考虑使用 不可变对象 来促进嵌套数据的快速比较。

此外,React.PureComponent 的 shouldComponentUpate() 会忽略整个组件的子级。请确保所有的子级组件也是”Pure”的。

继承的在constructor里面有两个方法:即为实例上调取constructor上面的两个方法:this.setState();//更改状态
this.forceUpdate();//强制更新。不更改状态也可以强制更新。

2.状态

自己在组件内部定义的。组件内部更新,可以通知组件重新更新,用this.setState。,可以控制内部渲染 ,不需要重新调取组件也可以重新渲染。
this.setState方法:不仅可以修改状态,还可以通知组件重新渲染。this.state虽然状态改变,但是不会渲染页面。但是我们可以强制渲染:this.forceUpDate();

组件重新渲染的方式:

  • 重新调取组件(或者重新调取的时候传递新的属性值)
  • 修改组件的状态
  • 操作DOM
  • forceUpDate
  • 。。。

轮播图

真实项目中我们创建组件一般都用类的方式,很少使用函数式创建。
1.类创建组件
有生命周期函数,
有实例:状态,上下文等都有
可以基于状态等信息控制组件重新渲染(调用组件,组件内容还是可以继续更新的)
2.函数组件
只有传递的属性,其他的都没有,生命周期,状态,上下文等都没有。
调用组件后,如果不重新调用,组件中的内容基本上是不修改的,静态组件。

项目中的问题

1.由于最后webpack把所有的css都合并在一起,开发时为了保证样式不冲突,需要保证每一个组件的最外层样式类唯一(命名规范:组件名+样式类名)

2.transition :在主栈中,以最后一次为准。所以不要放在主栈中,放在定时器当中,岔开节奏。
[toc]

REACT 1

安装包

npm root -g
后缀cmd是全局可执行的命令。
create-react-app 执行的是node_moules里面的index.js文件。
也可以直接考,除了考create-react-app文件,还有cmd文件。

npm install nrm -g
nrm ls:展开看到许多文件命令,看在哪个源下
然后nrm use cnpm 就可以直接使用的命令
cnpm就是淘宝镜像

yarn 不能安装在全局下,还是安装在本地的localstroge.

把安装在全局下,可以使用命令,因为全局安装会生成cmd的命令。如果安装在本地上,就需要自己在package里面的script里面配置一下模块。

但是如果想在如webpack想在项目中用,就在本地安装。
也可以自己去拷一下。文件夹和cmd命令文件。

swiper不支持es6的模板导入,所以报错。解决:在public文件里面建一个statlic,然后把index文档中,引入swiper的css和js,而且放到body里面。原因是webpack里面项目会自动编译到head标签里面,所以在编译之后加引入。但是在react.js中写的是window.Swiper。

开发环境(dev)和生产环境(prod)

复合组件

组件嵌套:父组件嵌套子组件
settings-editor-live templates-javascript-选中 模板
平行组件:没有嵌套关系的组件,包含兄弟组件
1.父组件把信息传递给子组件(复合组件信息传递)
父组件可以基于属性传递给子组件,(传递是单向的)父传子,子不能传父。对于嵌套层级较深的组件,可以依托这种范式一级级传递下去即可。
2.平行组件让拥有共同的父级组件,可以进行信息交互。我们可以让其拥有VOTE父组件,如果FOOTER把VOTE中的信息改了(子改动父),这样我们就可以让VOTE把最新修改的信息传递给body(父传子)
?子组件如何修改父组件的信息
父组件基于属性把自己的一个函数FN传递给子组件,子组件在某些操作下,把FN执行,而执行FN的过程我们就可以修改父组件中的一些信息了=>(原理类似于回调函数)
基于上下文管理传递的信息
因为上方的方法,的弊端:属性只能一层层传递,对于复杂的组件嵌套操作不方便,而且需要在调取组件的时候,把传递的属性一一列举才可以;

而上下文也是依托组件嵌套关系完成的,但是它的优势在于:当前组件(祖先)设置一些上下文,后代所有组件(儿子或者孙子等)都可以随时获取(不需要调取组件的时候一一传递,基于某些方法直接获取即可)这些信息使用。

REDUX

全局有一个公共的容器(所有组件都可以操作),我们可以在footer中把全局容器中的信息进行修改,而且只要全局信息修改,就可以通知所有用到该信息的组件重新渲染(类似于发布订阅)?REDUX就是这种解决方案:redux只有一个作用,就是为了实现组件之间的信息交互。

过程

有一个公共容器,存储需要共享的信息(仓库)->createStore ,在管理员中reducer,管理员就是用来修改容器中的公共状态。然后body如果需要这些公共信息的时候,从容器中获取状态信息用来展示即可,getState。footer想改变body的信息的时候,就通知管理员去修改状态(派发任务:通知管理员做具体的事情 dispatch)。
在容器中有天生自带的事件池,发布订阅,当容器中状态改变会通知事件池中的方法执行。而body想事件池中追加方法:方法执行控制body组件重新渲染即可,subscribe 监听。
总结:1.执行createstore,创建一个容器(store)用来管理公用的状态信息。创建一个事件池,用来存储一些方法(方法一般都是用来通知某个组件重新渲染的)。当容器中的状态改变,会自动通知事件池中的方法依次执行。2.基于store.getState可以获取容器中存储的状态信息(拿到状态信息就可以做数据绑定操作了)。3.我们可以基于store.subscribe向事件池中追加方法(也可以移除事件池的方法)。4.想要修改状态信息,首先雇一个管理员(reducer),它就是用来修改容器中状态的。当我们在组件中进行某些操作想要修改状态信息的时候,我们首先dispatch派发一个任务给reducer,并且告诉reducer,如何去修改状态信息。
状态信息都是reducer修改的。reducer记录了所有修改状态的行为范式,我们以后想要知道怎么改状态,只需要看reducer即可。

公共的框架信息,

yarn add redux react-redux 安装
redux:不局限于任何框架(vue/react/angular/jq....)
react-redux :把redux进一步封装,专门给react框架开发的,操作起来更加简洁。
vuex:类似于redux的操作思想,专门为vue框架定制的,
dua:把redux、react-redux进一步封装,操作更简洁
mobx:和redux不完全一致,也是用来管控公共状态的,只不过操作起来更加简单而已。

重要信息

jsx原理。ref轮播图,脚手架。redux。数组的扁平化,浅克隆,深度克隆的方案:常用的简单算法。

REDUX的工程化管理

1.reducer的模块化拆分:每一个模块有一个自己的对应的reducer,最后基于一些方法把所有的reducer合并即可。
2.基于ActionCreater统一管理每次派发需要的行为对象,而且和reducer一样,也是分版块管理的。
3.把dispatch和reducer校验时候需要的行为标识,进行统一管理。把容器的东西redux放在store文件夹里。

action文件夹中存放的是action-creater的内容 管理的行为对象

  • pesonal.js:personal版块的reducer
  • vote.js:vote版块的reducer
  • .....
  • index.js:把所有版块进行合并

reducer文件夹里存放的是每个版块的reducer

  • pesonal.js:personal版块的reducer
  • vote.js:vote版块的reducer
  • .....
  • index.js:把所有版块进行合并

action-types.js:存放的是项目中需要的所有的行为标识
index.js:创建store容器

使用redux开发:
1.把创建好的store挂载到上下文上,那个组件需要,则从上下文获取
2.需要获取store中的状态信息,我们需要机遇getstate获取,并且展示;为了容器状态更改组件重新渲染,我们还需要手动的subscribe。
3.需要派发的时候,我们自己还需要导入aciton,把对应模块中写的creator方法执行,手动dispatch一下。

为了简化基于redux开发时候,编写业务逻辑的代码,可以使用react-redux。
1.provider
我们把provider设置为当前项目的根组件,可以把store自动挂载到整个项目最外层根组件上下文中。项目所有其他组件都可以基于上下文获取store了。

把store作为属性,所有的子组件就作为Provider的内容。

2.connect
可以自动从provider上下文获取store。
可以把store中管理的状态,和action中管理的行为对象,都基于属性的方式传递给对应的组件。
当store中状态改变,自动重新渲染当前组件,不需要我们自己subscribe了。

高阶组件,一个组件里套了另一个组件。

react组件要

中间件

cnpm install redux-logger

代码

[toc]

React 项目

分类

课程版块:
课程列表
课程筛选
课程详情 (操作购物车按钮)

购物版块:

  • 购物车列表管理
  • 删除
  • 支付
  • 已支付列表

个人中心版块:
基本信息
登录
注册

公共部分:
头部导航
底部MENU

按模块划分,公共部分小组长

技术栈

  • 基于REACT实现spa单页面应用
    • react
    • react-dom
    • react-router-dom 实现路由切换
    • redux/react-redux/react-actions
    • axios
    • less
    • 公共组件 ant degin
    • 一些其他的插件
  • 团队的话基于GIT进行团队协作开发
  • 基于webpack进行项目编译部署
  • create-react-app

索要API接口文档,及设计稿/需求文档

搭建整个项目框架结构

|-src
|-api
|-index.js axios常规配置
|- course.js 课程版块的接口
|- personal.js 个人中心版块的接口
|- cart.js 购物车版块接口
| - component 公共组件
| - Nav.js
| - Menu.js
| - containers 业务组件 具体的页面
| - course
| - personal
| - cart
| - store dev mobels
| - actions
| - index.js
| - course.js
|- ..
| - reducers
| - index.js
| - course.js
|- ..
| - action-types.js
| - index.js

1.withCredentials 在cors跨域请求数据的时候,我们设置这个字段为true,是为了保证请求中可以携带资源凭证,最主要的凭证就是COOKIE.在xml.resposetext中默认为false

2.设置响应拦截器,把从服务器获取的信息进行拦截处理,把获取信息中的响应主体内容获取即可其余的信息我们一般不怎么操作。

axios.interceptors.response.use(result=>result.data);

当前配置支队post、put请求有效果.拦截通过请求逐日传递给服务器端的数据,默认传递的格式的是JSON格式,但是真实项目中url-encoded格式也较常用,如果服务器支持的是这种格式,我们在这里需要把信息做处理。

axios.defaults.transformRequst=(data={})=>{}

客户端和服务器信息通信,一般传递的数据格式有以下几种:
1.JSON格式
'{"A":"x","B":"y"}'
服务器返回给客户端的一般都是JSON格式。
但是客户端给服务端也有JSON格式的
2.X-WWW-FORMAT-URLENCODED
A=x&B=y&C=z....
客户端传递给服务器的数据格式一般都是这种格式。get系列请求问号传参,传递给服务器的就是这种格式,所有后台为了方便处理,可能会要求POST请求主体传递的数据格式也是这种格式。并且通过相关方法实现表单序列化后,得到的也是这种方式。。

3.qs 实现对象和url-encoded格式字符串相互转换的插件

4.Switch只能放自己创建的组件,并且是首字母大写,不能放正常的标签。
第一种

{/*<Switch>*/}
                {/*不能写正常的标签*/}
                {/*1*/}
                {/*<Nav/>*/}
                {/*2*/}
                {/*<Route path='/course' component={Course} />*/}
                {/*<Route path='/personal' component={Personal}/>*/}
                {/*<Route path='/cart' component={Cart}/>*/}
                {/*<Redirect to='/course'/>*/}
                {/*3*/}
                {/*<Menu/>*/}
            {/*</Switch>*/}

第二种:

<div>
                <header>
                    <Nav/>
                </header>
                <main>
                    <Switch>
                        <Route path='/course' component={Course} />
                        <Route path='/personal' component={Personal}/>
                        <Route path='/cart' component={Cart}/>
                        <Redirect to='/course'/>
                    </Switch>
                </main>
                <footer>
                    <Menu/>
                </footer>
            </div>

第三种

//=>解决方案二:把需要构建的结构全部放到APP组件中,在这个组件中控制自己的路由和结构
//=>INDEX
<HashRouter>
    <Switch>
        <App>
            <Route path='/course' component={Course}/>
            <Route path='/personal' component={Personal}/>
            <Route path='/cart' component={Cart}/>
        </App>
        <Redirect to='/course'/>
    </Switch>
</HashRouter>

//=>APP
render() {
    return <div>
        {/*HEADER-NAV*/}
        <header><Nav/></header>
        {/*MAIN-BODY*/}
        <main>
            {this.props.children}
        </main>
        {/*FOOTER-MENU*/}
        <footer><Menu/></footer>
    </div>;
}

一级路由和大框架:组长

5.虽然我们会把很多js程序都下载src中,但是有一些程度我们需要直接写在HTML页面中。
src中的东西最后会打包到一个js文件中,这样导致该js文件很大,页面接在的时候,需要一段时间才能加载完成。

我们很多程序相对简单,但是需要在html一加载就把它执行了,此时写在HTML中非常明智。
对于不支持COMMON.js或者ES6Module模块规范的,我们最好也写在HTML中的,例如swiper.js。
在项目中,为了避免样式冲突,我们需要保证:

  • 基于Less/sess这种有嵌套层级的预编译语言开发,
  • 最外层结构样式类名不要冲突,
  • 把里层的所有样式都嵌套到最外层样式的里面编写
    star
    基于NavLink实现路由切换的时候,路由可以切换,但是选中的样式并没有立即更新过来,只有页面重新刷新才会更新,这是为啥?
  • 路由切换把MAIN中的组件重新渲染,但是FOOTER中的组件始终是固定在底部的,每一次路由切换并不会重新渲染,所以选中样式无法更新。
  • 我们基于DOM操作自己控制样式类,也可以把整个组件用withRouter包起来,不要把connect包起来,一层层包裹并不好。

6.SEO优化技巧
SEO优化:一种让网站排名靠前的优化技巧,百度饲养了一个宠物,百度蜘蛛,百度爬虫,它会按照一定的规律定期收录你网站中的内容,当用户输入关键词搜索的时候,百度会把匹配的网站呈现出来,谁的这个关键词排名高,谁靠前,。
SEO竞价:一种让网站排名靠前的花钱技巧
1.给网站设置 title/keywords/description等、
2.h1只有一个,h1权重高,

项目经验:工作经历,时间。

推荐阅读更多精彩内容