慕课网学习笔记-揭秘一线互联网企业 前端JavaScript高级面试(双越)- 第7章 组件化和 React

begin

1、 说一下对组件化的理解

2、 jsx本质是什么

3、 jsx和vdom的关系

4、 说一下setState的过程

5、 阐述自己对react和vue的认识

todolist-demo

sudo cnpm i create-react-app -g

create-react-app react-test-me

npm start

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

src/App.js

import Todo from './components/todo/index.js';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Todo/>
      </div>
    );
  }
}

export default App;

src/components/index.js

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;

src/components/input/index.js

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(e) {
	    this.setState({
     	    title: e.target.value
	    })
	};
	clickHandle() {
		const title = this.state.title;
		const addTitle = this.props.addTitle;
		addTitle(title);
		// 把title添加进列表
		this.setState({
			title: ''
		})
	}
}

export default Input;

src/components/list/index.js

import React , { Component } from 'react';

class List extends Component {
	constructor(props) {
		super(props);
	};
	render() {
		const list = this.props.data;
		return (
              <div>
                <ul>
                  {
                  	list.map((item,index) => {
                  	    return <li key={index}>{item}</li>
                  	})
                  }
                </ul>
              </div>
			)
	}
}

export default List;

组件化-Component-based

说一下对组件化的理解

  • 组件的封装

  • 组件的复用

组件封装-component-package

组件的封装

  • 视图

  • 数据

  • 变化逻辑(数据驱动视图变化)

class Todo extends Component {
	constructor(props) {
		super(props);
		//数据封装-start
		this.state = {
			list: []
		}
		//数据封装-end
	};
	render() {
		return (
              /*视图封装-start*/
              <div>
                <Input addTitle={this.addTitle.bind(this)}/>
                <List data={this.state.list}/>
              </div>
              /*视图封装-end*/
			)
	};
	addTitle(title) {
	    const currentList = this.state.list;
       // 变化逻辑封装-start
	    this.setState({  
	        list: currentList.concat(title)
	    })
       // 变化逻辑封装-end
	}
}

组件复用-reuse

组件的复用:props传递、复用

<div>
	<Input addTitle={this.addTitle.bind(this)}/>
	<List data={this.state.list}/>
	<List data={this.state.list}/>
	<List data={this.state.list}/>
</div>
class List extends Component {
	render() {
		const list = this.props.data;
		return (
              <div>
                <ul>
                  {
                  	list.map((item,index) => {
                      return <li key={index}>{item}</li>
                  	})
                  }
                </ul>
              </div>
			)
	}
}

JSX本质

jsx语法

jsx解析成JS

独立的标准

JSX语法演示

  • HTML形式

  • 引入JS变量和表达式

  • if..else…

  • 循环

  • style和className

  • 事件

render() {
  const name="zhangsan";
  const show = true;
  const list = [];
  const styleConfig = {
    color: 'blue',
    fontSize: '40px'
  }
  
  return (
    <div  className="container">
       {/*注释*/}
       <p>{name}</p>
       <p>{name ? 1 : 0}</p>
       <p>{(name === '').toString()}</p>
       <p>{name || 'lisi'}</p>
       
       {show ?  <img src=''/>:" "}
       
       <ul>
          {list.map((item,index) => {
            return <li key={index}>{item}</li>
          })}
       </ul>
       
       <p style={styleConfig}>hello</p>
    </div>
	)
};

JSX解析成JS

jsx语法根本无法被浏览器所解析

那么它如何在浏览器运行

React.createElement('div', {id: 'div1'}, child1,child2,child3)
React.createElement('div', {id: 'div1'}, [...])

jsx其实是语法糖

开发环境会将jsx编译成JS代码

jsx的写法大大降低了学习成本和编码工作量

JSX标准

jsx独立的标准

  • jsx 是React引入的,但不是React独有的

  • React 已经将它作为一个独立标准开放,其他项目也可用

  • React.createElement 是可以自定义修改的

  • 说明:本身功能已经完备;和其他标准兼容和扩展性没问题

JSX和vdom

分析:为何需要vdom

React.createElement 和 h

何时 patch ?

自定义组件的解析

vdom回顾

为何需要vdom

  • vdom 是React 初次推广开来的,结合jsx

  • jsx就是模板,最终要渲染成 html

  • 初次渲染 + 修改 state 后的 re-render

  • 正好符合vdom 的应用场景

何时patch

  • 初次渲染 - ReactDOM.render(, container)

  • 会触发patch(container,vnode)

  • re-render-setState

  • 会触发patch(vnode, newVnode)

// patch(container,vnode)
ReactDOM.render(<App />, document.getElementById('root'));

// patch(vnode, newVnode)
this.setState({
  list: currentList.concat(title)
})

自定义组件的处理-Custom

<div>
    <List data={this.state.list}/>
</div>
React.createElement('div',null,
  React.createElement(Input,{data:this.state.list})
)
// var list = new List({data: this.state.list});
// var vnode = list.render()

自定义组件创建

‘div’ - 直接渲染 <div> 即可,vdom可以做到

Input 和 List ,是自定义组件(class),vdom 默认不认识

因此 Input 和 List 定义的时候必须声明render函数

根据props初始化实例,然后执行实例的render函数

JSX和vdom-总结

  • 为何需要vdom: JSX 需要渲染成HTML,数据驱动视图

  • React.createElement 和 h, 都生成 vnode

  • 何时patch:ReactDOM.render()和setState

  • 自定义组件的解析:初始化实例,然后执行render

setState

说一下 setState的过程

  • setState 的异步

  • vue修改属性也是异步

  • setState的过程

setState-异步

setState为何需要异步?

  • 可能会一次执行多次setState

  • 你无法规定、限制用户用户如何使用setState

  • 没必要每次setState都重新渲染,考虑性能

  • 即便是每次重新渲染,用户也看不到中间的效果

addTitle(title) {
  const currentList = this.state.list;       
  console.log(this.state.list); // ['a','b']
  this.setState({
  	  list: currentList.concat(title)
  }); // 'c'
  console.log(this.state.list); // ['a','b']
}
addTitle(title) {
  const currentList = this.state.list;   
  this.setState({
  	  list: currentList.concat(title)
  }); 
  this.setState({
  	  list: currentList.concat(title + 1)
  });
  this.setState({
  	  list: currentList.concat(title + 2)
  });  // 只执行最后这一个,之前的不执行
} 

回顾vue修改属性

第四步:data 属性变化

  • 修改属性,被响应式的set监听到

  • set中执行updateComponent // 这里是异步的

  • updateComponen 重新执行vm._render()

  • 生成的vnode和prevVnode,通过patch进行对比

  • 渲染到HTML中

setState过程

每个组件实例,都有renderComponent方法

执行renderComponent会重新执行实例的render

render函数返回newVnode,然后拿到preVnode

执行patch(preVnode,newVnode)

React 和 Vue对比

  • 两者的本质区别

  • 看模板和组件化的区别

  • 两者共同点

  • 总结问题答案

两者的本质区别

  • vue - 本质是MVVM框架,由MVC发展而来

  • React - 本质是前端组件化框架,由后端发展而来

  • 但这并不妨碍他们两者都能实现相同的功能

看模板和组件化的区别

  • vue - 使用模板(最初由angular)

  • React - 使用JSX

  • 模板语法上,更倾向于JSX

  • 模板分离上,更倾向于vue

  Vue React
框架类型 mvvm mvc
构建工具 vue-cli flux
编写方式 模板 JSX
状态管理 vuex redux
移动端 Weex React Native

模板的区别一

vue

<div>
    <h1 v-if="ok">Yes</h1>
    <h1 v-else>No</h1>
</div>

react

<div>
  {ok ? <h1>Yes</h1> : <h1>No</h1>}
</div>

vue

<ul id="example-1">
  <li v-for="item in items">
    
  </li>
</ul>

react

<ul id="example-1">
  {
    items.map((item, index) => {
      return <li key={key}>{item.message}</li>
    })
  }
</ul>

jsx {大括号} 里面放JS变量或者表达式

模板的区别二

react 的模板和JS混在一起,未分离

<div>
  <Input addTitle={this.addTitle.bind(this)}/>
  <List data={this.state.list}/>
</div>

模板应该和JS逻辑分离,回顾“开放封闭原则”

组件化的区别

React本身就是组件化,没有组件化就不是React

vue也支持组件化,不过是在MVVM上的扩展

对于组件化,更倾向于React,做的彻底而清晰

两者共同点

  • 都支持组件化

  • 都是数据驱动视图

相似之处:都是javascript框架,有路由、状态管理、构建工具等、组件式开发。都用到了Virtual DOM。

Virtual DOM是一个映射真实DOM的javascript对象,如果需要改变任何元素的状态,则先在virtual DOM上改变,而不是直接改变真实的DOM。当有变化产生时,一个新的虚拟节点便会被创建,同时计算新旧虚拟结点之间的差别,最后映射真实的dom节点。

问题解答

国内使用,首推vue。文档更易读、易学、社区够大

如果团队水平较高,推荐使用React。组件化和JSX做的更好

React 还是 Vue: 你应该选择哪一个Web前端框架?

更多-more

揭秘一线互联网企业 前端JavaScript高级面试