组件化和 React
一,对组件化的理解
1,组件的封装
-视图
-数据
-变化逻辑(数据驱动视图变化)
例:
import React, {
Component
} from 'react';
import List from './list/index.js';
import Input from './input/index.js'; class Todo extends Component {
constructor(props) {
// 数据
super(props)
this.state = {//保存当前组件的变量
list:[]
}
}
render() {
return (
// 视图
<div>
<Input addTitle={this.addTitle.bind(this)}/>
<List data={this.state.list} />
<List data={[1,2,3]} />
</div>
)
}
// 变化逻辑
addTitle(title) {
const currentList = this.state.list;
this.setState({
list:currentList.concat(title)
})
}
} export default Todo
2,组件的复用
-props传递
-复用
例:
import React, {
Component
} from 'react'; class List extends Component {
constructor(props) {
super(props)
}
render(){
const list = this.props.data; //props传递
return (
<ul>
{
list.map((item,index) => {
return <li key={index}>{item}</li>
})
}
</ul>
)
}
} export default List
二,JSX本质
1,JSX语法:
例:
// html形式
// 引入JS变量和表达式
// if...else...
// 循环
// style和className
// 事件
render() {
const name = '12';
const show = true;
const list = [1,2,3,4,5];
const styleConfig = {
fontSize:'40px',
color:'blue'
}
return (
<div className='container'>
{/* <Todo /> */}
<p>{name}</p>
<p>{name ? 1 : 0}</p>
<p>{(name === '12').toString()}</p>
<p>{name || 'lisi'}</p>
{show ? <img src='./logo.svg' /> : ''}
<ul>
{list.map(function(item,index) {
return <li key={index}>{item}</li>
})}
</ul>
<p style={styleConfig}>this is a p</p>
<p style={{fontSize:'40px',color:'blue'}}>this is a p</p>
</div> );
2,JSX解析成JS:
JSX语法根本无法被浏览器所解析,那么它如何在浏览器运行?-转换成JS运行
思考:为何react组件中,React 没有显示地使用,但却必须要引入?(去掉的话会报错) 'React' must be in scope when using JSX
import React, {
Component
} from 'react';
看个例子:
// JSX代码
var profile = <div>
<img src="avatar.png" className="profile" />
<h3>{[user.firstName,user.lastName].join('')}</h3>
</div>;
解析结果:
// 解析结果 有没有跟vdom的h函数、vue的_c函数很像?yes!
var profile = React.createElement("div",null,
React.createElement("img",{src:"avatar.png",className:"profile"}),
React.createElement("h3",null,[user.firstName,user.lastName].join('')),
);
从上面得知,我们所写的JSX代码,都是需要通过 React.createElement 函数来解析
ReactElement createElement(
string/ReactClass type,
[object props],
[children ...]
)
(类似 vdom 的 h 函数、vue 的 _c 函数)例:
React.createElement('div',{id:'div1'},child1,child2,child3)
React.createElement('div',{id:'div1'},[...])
再看:
render(){
const list = this.props.data;
return (
<ul>
{
list.map((item,index) => {
return <li key={index}>{item}</li>
})
}
</ul>
)
}
解析如下:
function render() {
const list = this.props.data;
return React.createElement(
'ul',
null,
list.map((item,index) => {
return React.createElement(
'li',
{key:index},
item
)
})
)
}
JSX的写法大大降低了学习成本和编码工作量
同时,JSX也会增加debug成本
3,独立的标准
JSX 是 React 引入的,但不是 React 独有的,已经是一个标准
React 已经将它作为一个独立标准开放,其他项目也可以使用
React.createElement 是可以自定义修改的
说明:本身功能已经完备;和其他标准兼容和扩展性没问题
使用插件编译jsx代码,测试:
新建文件夹 jsx-test
mkdir jsx-test
进入文件夹
cd jsx-test
初始化:
npm init
新建文件 demo.jsx
touch demo.jsx
全局安装babel
sudo npm i babel -g
安装依赖插件
npm install --sav-dev babel-plugin-transform-react-jsx
创建.babelrc文件,配置:
{
"plugins":["transform-react-jsx"]
}
babel编译命令:
babel --plugins transform-react-jsx demo.jsx
demo.jsx代码如下:
class Input extends Component {
constructor(props) {
super(props)
this.state = {
title:''
}
}
render(){
return (
<div>
<input value={this.state.title} onChange={this.changeHandle.bind(this)} />
<button onClick={this.clickHandle.bind(this)}>submit</button>
</div>
)
}
changeHandle(event){
this.setState({
title:event.target.value
})
}
}
编译结果:
class Input extends Component {
constructor(props) {
super(props);
this.state = {
title: ''
};
}
render() {
return React.createElement(
'div',
null,
React.createElement('input', { value: this.state.title, onChange: this.changeHandle.bind(this) }),
React.createElement(
'button',
{ onClick: this.clickHandle.bind(this) },
'submit'
)
);
}
changeHandle(event) {
this.setState({
title: event.target.value
});
}
}
尝试把 React.createElement 改成 h 在文件顶部加入
/* @jsx h */
运行编译如下:
class Input extends Component {
constructor(props) {
super(props);
this.state = {
title: ''
};
}
render() {
return h(
'div',
null,
h('input', { value: this.state.title, onChange: this.changeHandle.bind(this) }),
h(
'button',
{ onClick: this.clickHandle.bind(this) },
'submit'
)
);
}
changeHandle(event) {
this.setState({
title: event.target.value
});
}
}
总结:
js语法(标签,js表达式,判断,循环,事件绑定)
JSX其实是语法糖(微创新),需被解析成JS才能运行,React.createElement
已经成为独立的标准
三,JSX 和 vdom 关系
1,分析:为何需要vdom
vdom是 React 初次推广开来的,结合 JSX
JSX 就是模版,最终要渲染成 html
初次渲染 + 修改 state 后的 re-render
正好符合 vdom 的应用场景
2,React.createElement 和 h(本质一样)
所有的JSX都要解析成JS,执行最终返回vnode
3,何时 patch ?
(1),初次渲染 ReactDOM.render(<App />, container),会触发 patch(container,vnode)
例:
ReactDOM.render(<App />, document.getElementById('root'));
(2),re-render - setState,会触发 patch(vnode,newVnode)
// patch(vnode,newVnode)
this.setState({
list:currentList.concat(title)
})
4,自定义组件的解析
'div',直接渲染<div>即可,vdom可以做到
Input和List等自定义组件(class),vdom默认不认识
因此Input和List定义的时候必须声明render函数
根据props初始化实例,然后执行实例的render函数
render函数返回的还是vnode对象
var list = new List({ data: this.state.list });
var vnode = list.render();
例(demo.jsx)
import List from './list/index.js';
import Input from './input/index.js'; function render() {
return (
// 视图
<div>
<p> this is demo </p>
<Input addTitle={this.addTitle.bind(this)}/>
<List data={this.state.list} />
<List data={[1,2,3]} />
</div>
)
}
解析如下:
import List from './list/index.js';
import Input from './input/index.js'; function render() {
return (
// 视图
React.createElement(
'div',
null,
React.createElement(
'p',
null,
' this is demo '
),
React.createElement(Input, { addTitle: this.addTitle.bind(this) }),
React.createElement(List, { data: this.state.list }),
React.createElement(List, { data: [1, 2, 3] })
)
);
}
总结:
为何需要vdom:JSX需要渲染成html,数据驱动视图
React.createElement 和 h,都生成vnode (React.createElement 既可以创建 html 默认的标签-字符串形式,可以创建自定义组件名称)
何时patch:ReactDOM.render(...) 和 setState()
自定义组件的解析:初始化实例,然后执行render
四,说下 setState 的过程 ( setState 核心函数)
1,setState 的异步
addTitle(title) {
const currentList = this.state.list;
// patch(vnode,newVnode)
console.log(this.state.list); //[1,2]
this.setState({
list: currentList.concat(title) //3
})
console.log(this.state.list); //[1,2] 因为上面的setState是异步操作,所以这里仍旧是[1,2]
}
原因:
01,可能会一次执行多次 setState
02,你无法规定、限制用户如何使用 setState
03,没必要每次 setState 都重新渲染,考虑性能
04,即便是每次重新渲染,用户也看不到中间的效果(js执行和DOM渲染是单线程的)
05,只看到最后的结果即可
addTitle(title) {
const currentList = this.state.list;
// 初次想增加 title
this.setState({
list: currentList.concat(title)
}) // 改变注意,想增加 title + 1
this.setState({
list: currentList.concat(title + 1)
}) // 又改变注意,想增加 title + 2
this.setState({
list: currentList.concat(title + 2)
})
}
用户操作后,只会看到最后的结果,即 list: currentList.concat(title + 2)
2,vue 修改属性也是异步
01,效果、原因和 setState 一样
02,对比记忆,印象深刻
03,复习下vue 的实现流程
第一步:解析模版成render函数
第二步:响应式开始监听
第三步:首次渲染,显示页面,且绑定依赖
第四步:data 属性变化,触发 rerender ( set中执行updateComponent 是异步的)
3,setState 的过程
01,每个组件实例,都有 renderComponent 方法 (在Component 组件中定义的)
02,执行 renderComponent 会重新执行实例的 render )
03,render 函数返回 newVnode,然后拿到 preVnode (上次执行的 newVnode)
04,执行 patch(preVnode,newVnode)
addTitle(title) {
const currentList = this.state.list;
// patch(vnode,newVnode)
console.log(this.state.list); //[1,2]
this.setState({
list: currentList.concat(title) //3
},() => {
console.log(this.state.list); //这里能拿到实时结果 [1,2,3]
// this.renderComponent()
})
console.log(this.state.list); //[1,2] 因为上面的setState是异步操作,所以这里仍旧是[1,2]
}
模拟 Component
class Component {
constructor(props) { }
renderComponent() {
const preVnode = this._vnode;
const newVnode = this.render();
patch(preVnode,newVnode)
this._vnode = newVnode; }
}
五,对 React 和 vue 的认识
国内使用,首推vue,文档更易读、易学,社区够大
如果团队水平较高,推荐使用React,组件化和JSX做的更好
1,两者的本质区别
vue-本质是MVVM框架,由MVC发展而来
React-本质是前端组件化框架,由后端组件化发展而来
但这并不妨碍它们两者都能实现相同的功能
2,模版的区别:
vue-使用模版(最初由 angular 提出)
React-使用JSX
模版语法上,更倾向于JSX
模版分离上,更倾向于Vue
3,组件化的区别:
React本身就是组件化,做的更彻底
vue也支持组件化,不过是在MVVM上的扩展
4,两者共同点
都支持组件化
都是数据驱动视图
六,总结:
组件化的理解:
1,组件的封装:封装视图,数据,变化逻辑
2,组件的复用:props传递,复用
JSX本质:
1,语法
2,语法糖,需被解析成JS才能运行
3,JSX是独立的标准,可被其他项目使用
JSX和vdom的关系
1,为何需要vdom:JSX需要渲染成html,还有rerender
2,React.createElement 和 h,都生成vnode
3,何时patch:ReactDOM.render() 和 setState
4,自定义组件的解析:初始化实例,然后执行render
setState过程:
异步:效果、原因 (vue修改属性也是异步,效果、原因)
setState的过程:最终走到 patch(preVnode,newVnode)
附:用 React 实现 todo-list
创建 React 开发环境
全局安装
sudo npm i create-react-app -g --registry=https://registry.npm.taobao.org
运行
create-react-app react-rest
成功之后:
Inside that directory, you can run several commands: yarn start
Starts the development server. yarn build
Bundles the app into static files for production. yarn test
Starts the test runner. yarn eject
Removes this tool and copies build dependencies, configuration files
and scripts into the app directory. If you do this, you can’t go back! We suggest that you begin by typing: cd react-rest
yarn start Happy hacking!
进入文件夹
cd react-rest
运行
yarn start
实现todo组件
import React, {
Component
} from 'react';
import List from './list/index.js';
import Input from './input/index.js'; class Todo extends Component {
constructor(props) {
super(props)
this.state = {//保存当前组件的变量
list:[]
}
}
render() {
return (
<div>
<Input addTitle={this.addTitle.bind(this)}/>
<List data={this.state.list} />
</div>
)
}
addTitle(title) {
const currentList = this.state.list;
this.setState({
list:currentList.concat(title)
})
}
} export default Todo
todo中使用的Input组件:
import React, {
Component
} from 'react'; class Input extends Component {
constructor(props) {
super(props)
this.state = {
title:''
}
}
render(){
return (
<div>
<input value={this.state.title} onChange={this.changeHandle.bind(this)} />
<button onClick={this.clickHandle.bind(this)}>submit</button>
</div>
)
}
changeHandle(event){
this.setState({
title:event.target.value
})
}
clickHandle(){
const title = this.state.title;
// 把title添加进列表
const addTitle = this.props.addTitle;
addTitle(title);//重点
this.setState({
title:''
}) }
} export default Input
todo中使用的List组件
import React, {
Component
} from 'react'; class List extends Component {
constructor(props) {
super(props)
}
render(){
const list = this.props.data;//list组建期望别人传入的列表
return (
<ul>
{
list.map((item,index) => {
return <li key={index}>{item}</li>
})
}
</ul>
)
}
} export default List
最后,修改App.js
import React, {
Component
} from 'react';
import logo from './logo.svg';
import './App.css';
import Todo from './components/todo/index.js' class App extends Component {
render() {
return (
<div>
<Todo />
</div>
);
}
} export default App;
附:
react 父子组件互相通信
1,父组件向子组件传递 在引用子组件的时候传递,相当于一个属性
<Input addTitle={this.addTitle.bind(this)} />
<List data={this.state.list} />
2,子组件向父组件传递 子组件通过 调用父组件传递到子组件的方法 向父组件传递消息的。
class Input extends Component {
constructor(props) {
super(props)
this.state = {
title:''
}
// console.log(this.props)
}
render(){
return (
<div>
<input value={this.state.title} onChange={this.changeHandle.bind(this)} />
<button onClick={this.clickHandle.bind(this)}>submit</button>
</div>
)
}
changeHandle(event){
this.setState({
title:event.target.value
})
}
clickHandle(){
const title = this.state.title;
// 把title添加进列表
const addTitle = this.props.addTitle;
addTitle(title);//重点 调用父组件方法
this.setState({
title:''
}) }
}
附:
React:Rethinking Web App Development at Facebook 只负责view层,不是完整的MVVM框架
React 特点:轻,组件化开发,高度可重用
React应用场景:
复杂场景下的高性能
重用组件库,组件组合
React组件的生命周期和事件处理
React Components Lifecycle
Mounted: React Components 被render解析,生成对应的DOM节点,并被插入浏览器的DOM结构的一个过程( React.renderComponent() )
Update:一个 mounted 的 React Components 被重新render 的过程 (setState() 或者 setProps() ----> render)
Unmounted:一个mounted的 React Components 对应的 DOM 节点被从DOM结构中移除的过程
每一个状态 React 都封装了对应的 hook 函数
未完待续...
组件化和 React的更多相关文章
- client高性能组件化框架React简单介绍、特点、环境搭建及经常使用语法
[本文源址:http://blog.csdn.net/q1056843325/article/details/54729657 转载请加入该地址] 明天就是除夕了 预祝大家新春快乐 [ ]~( ̄▽ ̄) ...
- 【前端知识体系-JS相关】组件化和React
1. 说一下使用jQuery和使用框架的区别? 数据和视图的分离,(jQuery数据和视图混在一起,代码耦合)-------开放封闭原则 以数据驱动视图(只关注数据变化,DOM操作被封装) 2.说一下 ...
- React Native 之 组件化开发
前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...
- 从DOM操作看Vue&React的前端组件化,顺带补齐React的demo
前言 接上文:谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo 上次写完博客后,有朋友反应第一内容有点深,看着迷迷糊糊:第二是感觉没什么使用场景,太过业务化,还不如直接写Vue ...
- 谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo
前言 前端已经过了单兵作战的时代了,现在一个稍微复杂一点的项目都需要几个人协同开发,一个战略级别的APP的话分工会更细,比如携程: 携程app = 机票频道 + 酒店频道 + 旅游频道 + ..... ...
- 移动web端的react.js组件化方案
背景: 随着互联网世界的兴起,web前端开发的方式越来越多,出现了很多种场景开发的前端架构体系,也对前端的要求日益增高,早已经不是靠一个JQuery.js来做前端页面的时代了,而今移动端变化最大,近 ...
- React 面向组件化编程 - 封装了webpack - npm run build 产生的包的 /static 引用路径问题
React 面向组件化编程 面向对象 ----> 面向模块 ----> 面向组件 套路: 注意: 组件名必须大写开头: 只能有一个根标签: <input />虚拟DOM 元素必 ...
- 前端开发组件化设计vue,react,angular原则漫谈
前端开发组件化设计vue,react,angular原则漫谈 https://www.toutiao.com/a6346443500179505410/?tt_from=weixin&utm_ ...
- atitit.React 优缺点 相比angular react是最靠谱的web ui组件化方案了
atitit.React 优缺点 相比angular react是最靠谱的web ui组件化方案了 1. React的组件化才是web ui部件的正确方向1 1.1. 组件化集成html ,css ...
随机推荐
- Android Studio向项目中导入jar包的方法
第一步: 切换到"Project"视图,找到app --> libs目录 第二步: 将需要导入的jar包粘贴到libs目录中,此时还不能看到jar包中的内容 第三步: 右键点 ...
- Go语言运算符
目录 算术运算符 注意事项 赋值运算符 逻辑运算符 短路与和短路或 关系运算符 位运算符 其他运算符 运算符优先级 运算符用于在程序运行时执行数学或逻辑运算. Go 语言内置的运算符有:算术运算符.赋 ...
- 第十八节:详解Java抽象类和接口的区别
前言 对于面向对象编程来说,抽象是它的特征之一. 在Java中,实现抽象的机制分两种,一为抽象类,二为接口. 抽象类为abstract class,接口为Interface. 今天来学习一下Java中 ...
- Java学习笔记42(序列化流)
对象中的数据,以流的形式,写入到文件中保存 过程称为写出对象,对象的序列化 ObjectOutputStream将对象写到文件中,实现序列化 在文件中,以流的形式,将对象读取出来, 读取对象,对象的反 ...
- 从app上传图片到php,再上传到java后端服务器的方法一条龙服务
在现在的网络开发中,上传图片类的需求实在是太普通不过了,但是对于怎么样做到上传图片,对于刚开始建立项目的时候,还是有点不知所措的.也许有幸,我们做的项目是之前已经有人写过类似的用例了,那么我们只需要依 ...
- 卖给高通之后的CSR的现状和未来
转眼之间,CSR已经嫁给高通两年了,养在深宫大院大小妾的CSR,到底过的怎么样呢? 从高通官网上查看的结果显示,CSR产品被分成了三类: A 传统的用在耳机音响的CSR86XX系列,这部分改动不大,就 ...
- 如何在IDEA里给大数据项目导入该项目的相关源码(博主推荐)(类似eclipse里同一个workspace下单个子项目存在)(图文详解)
不多说,直接上干货! 如果在一个界面里,可以是单个项目 注意:本文是以gradle项目的方式来做的! 如何在IDEA里正确导入从Github上下载的Gradle项目(含相关源码)(博主推荐)(图文详解 ...
- C#7.0--引用返回值和引用局部变量
一.在C#7.0以上版本中,方法的返回值可以通过关键字ref指定为返回变量的引用(而不是值)给调用方,这称为引用返回值(Reference Return Value,或ref returns): 1. ...
- Vue + Element UI 实现权限管理系统 前端篇(十三):页面权限控制
权限控制方案 既然是后台权限管理系统,当然少不了权限控制啦,至于权限控制,前端方面当然就是对页面资源的访问和操作控制啦. 前端资源权限主要又分为两个部分,即导航菜单的查看权限和页面增删改操作按钮的操作 ...
- Eureka多机高可用
线上Eureka高可用集群,至少三个节点组成一个集群,推荐部署在不同的服务器上,IP用域名绑定,端口保持一致. 10.1.22.26:876210.1.22.27:876210.1.22.28:876 ...