组件化和 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 ...
随机推荐
- 通过shell快速配置J2EE运行环境
虽然可以通过已经配置好的docker镜像来快速运行相关环境, 但是 现实往往就是这么残酷+有钱很任性的时候 就是给出了一个装好系统的电脑让配置环境,每次的配置环境变量真的很烦 纯体力活 就简单的写个脚 ...
- IDEA 图标介绍。 缓存和索引介绍、清理方法和Debug使用
一.图标 二.缓存和索引 IntelliJ IDEA 的缓存和索引主要是用来加快文件查询,从而加快各种查找.代码提示等操作的速(上图中的图标能这样显示也是靠索引).某些特殊条件下,IntelliJ I ...
- python库函数Map, Filter and Reduce的用法
python中有三个函数式编程极大的简化了程序的复杂性,这里就做一下讨论和记录. 一 Map:应用在链表输入所有元素的函数,它的格式如下所示: map(function_to_apply, list_ ...
- cracking the coding interview系列C#实现
原版内容转自:CTCI面试系列——谷歌面试官经典作品 | 快课网 此系列为C#实现版本 谷歌面试官经典作品(CTCI)目录 1.1 判断一个字符串中的字符是否唯一 1.2 字符串翻转 1.3 去除 ...
- [源码]python Scapy Ftp密码嗅探
[源码]python Scapy Ftp密码嗅探 原理很简单,FTP密码明文传输的 截取tcp 21端口User和Pass数据即可 Scapy框架编译程序较大(一个空程序都25M),所以就不提供exe ...
- 超级详细使用Webpack4.X 搭建H5开发环境
超级详细使用Webpack4.X 搭建H5开发环境 会撸码的小马 关注 2018.05.29 17:17* 字数 603 阅读 6453评论 0喜欢 5 很久没弄博客了,这两天有点时间来搞一下最近在弄 ...
- C# log4net 使用
利用log4net写入异常类日志,在网上搜索一阵之后便想记录下来,以便后期使用,同时希望帮到大家. 第一步:使用管理NuGet程序包导入log4net.dll 导入成功后会在引用下显示相应的log4 ...
- 13-03 Java 基本类型包装类概述,Integer类,Character
基本类型包装类概述 将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据.常用的操作之一:用于基本数据类型与字符串之间的转换.基本类型和包装类的对应Byte,Short,Inte ...
- (转)mtr命令详解诊断网络路由
原文:https://blog.51cto.com/6226001001/1941355 http://www.zzbiji.com/2212.html----Linux下使用mtr做路由图进行网络分 ...
- mybatis随笔五之Executor
在上一篇文章我们分析到了mapper接口方法的实现实际上是交由代理类来实现的,并最终调用Executor来查询,接下来我们对executor.query(ms, wrapCollection(para ...