文章目录
React
MVC MVP MVVM
Web设计模式,通过分离模块来改进代码的组织方式。
MVC 是 Model View Controller 的缩写。
- Model:模型层,数据相关的操作。
- View:视图层,用户界面渲染逻辑。
- Controller:控制器,数据模型和视图之间通信的桥梁。
MVC 模型把视图渲染和数据处理做了隔离,通过控制器接收视图操作,传递给数据模型,数据处理后由数据模型驱动视图渲染。
MVP 是 Model View Presenter 的缩写,可以说是 MVC 模式的改良。
- Model、View依然负责数据和视图
如果 Model 只想做数据相关的操作,把通知 View 的逻辑挪到了 Control 里,这时 Control 摇身一变称为了 Presenter。因为解耦了 Model 和 View,也使得它们的职责划分更加清晰。
MVVM 是 Model View - ViewModel 的缩写,ViewModel 主要靠 DataBinding 把 View 和 Model 做了自动关联,框架替应用开发者实现数据变化后的视图更新。
MVVM与MVC最大的区别:实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变。
React 并不是严格意义上 MVC MVVM 这种前端架构模式,它更像一种视图层的库。在传统的 MVC、MVP、MVVM 等架构模式中,通常会将应用程序的逻辑分成不同的部分,比如模型(Model)、视图(View)和控制器(Controller)、展示器(Presenter)或视图模型(ViewModel)等,每个部分都有不同的职责和作用。而在 React 中,它更倾向于将界面拆分成多个可重用的组件,每个组件负责管理自己的状态和 UI,而不是像传统的架构模式那样严格分离模型和视图。
但它仍然可以与这些模式结合使用。例如,可以将 React 组件作为视图层,结合其他库或框架来管理应用程序的模型和控制器逻辑。
Vue.js 更偏向于模型-视图-视图模型(MVVM),但并不是严格遵循,而是借鉴并结合自己的特点。
单/双向数据绑定
单向数据绑定:Model 的更新会触发 View 的更新,View 的更新不会触发 Model 的更新,它们的作用是单向的。
双向数据绑定:Model 的更新会触发 View 的更新,View 的更新也会触发 Model 的更新,它们的作用是相互的
React 是单向数据绑定,当用户访问 View 时,通过触发 Events 进行交互,而在相应 Event Handlers 中,会触发对应的 Actions,而 Actions 通过调用 setState 方法对 View 的 State 进行更新,State 更新后会触发 View 的重新渲染。可以看出,在 React 中,View 层是不能直接修改 State,必须通过相应的 Actions 来进行操作。
Vue 支持单向数据绑定和双向数据绑定
- 单向数据绑定:使用v-bind属性绑定、v-on事件绑定或插值形式{{data}}。
- 双向数据绑定:使用v-model指令,用户对View的更改会直接同步到Model。
双向绑定的优缺点:
优点:比较方便简单。
缺点:属于暗箱操作,无法很好的追踪数据变化。
React 和 Vue 都只是单向数据流,虽然 Vue 有双向数据绑定,但是 Vue 父子组件之间数据传递仍然遵循单向数据流。
React特点
React 是一个用于构建用户界面的 JS 库。React 起源于 Facebook 的内部项目,用来架设 Instagram 网站,并于 2013 年 5 月开源。
特点:
- 遵循组件设计模式
- 使用虚拟DOM来高效操作DOM
- 实现了单向响应数据流
- JSX 是 JavaScript 语法的扩展, 可以直接在 JS 中写 XML 语法。
JSX
JSX即Javascript XML,它是对JS的语法扩展,可以直接在JS中写XML语法,JSX会将类似XML的语法转化为原生的JS。要在JSX中执行JS,需要写在{}中。
为了使浏览器能够读取 JSX,需要用像 Babel 这样的 JSX 转换器将 JSX 文件转换为 JavaScript 对象,然后再将其传给浏览器。
JSX 结构最终会被翻译为 React.createElement 的结构。
组件和不同类型
React 中一切都是组件,我们通常将应用程序的整个逻辑分解为小的单个部分,每个单独的部分称为组件。
组件类型:
按状态分为无状态组件和有状态组件:
无状态组件也被称为"纯函数组件",就是不维护自己的state,只负责接收props渲染DOM。
对于这种无状态的组件,使用函数式的方式声明,会使得代码的可读性更好,并能大大减少代码量。
注:函数组件没有生命周期。(React Hooks 提供了一种在无需编写 class 的情况下使用 state 和其他 React 特性的方式。Hooks 使得在函数组件中引入和复用 state、生命周期方法等)
const Todo = (props) => (
<div onClick={props.onClick}>{props.text}</div>
)
有状态组件就是组件内部包含状态 state。有状态组件通常会带有生命周期lifecycle,用以在不同的时刻触发状态的更新。
class Hello extends React.Component{
constructor(props){
super(props);
this.state = {
tips: "Hello World!"
}
}
componentDidMount() {
console.log("ComponentDidMount", this);
}
render() {
return (
<div>{this.state.tips}</div>
);
}
应用场景:无状态组件更加简单,适用于展示性组件(比如图片等不需要存数据的),而有状态组件更适合处理复杂逻辑、数据管理和需要内部状态的情况。
按受控可以分为受控组件和非受控组件,主要场景是在表单中:
受控组件:表单元素的值(例如输入框、复选框、下拉框等)由 React 组件的 state 来管理,通过事件处理函数来更新 state,并将 state 的值绑定到表单元素的 value 属性。
import React, { useState } from 'react';
function ControlledComponent() {
const [inputValue, setInputValue] = useState('');
const handleChange = (event) => {
setInputValue(event.target.value);
};
return (
<input
type="text"
value={inputValue}
onChange={handleChange}
/>
);
}
非受控组件:在非受控组件中,表单元素的值不受 React state 的控制,而是由 DOM 元素自身来管理。通常是通过 ref 来获取表单元素的引用,然后直接在原生 DOM 元素上操作。
function UncontrolledCompenent() {
const inputRef = useRef();
const handleClick = () => {
alert(`Input value: ${inputRef.current.value}`);
}
return (
<div>
<input type="text" ref={inpuutRef} />
<button onClick={handleClick}>Get Input Value</button>
</div>
)
}
应用场景:受控组件适用于需要对表单元素进行更细粒度控制、数据验证和处理的场景。非受控组件适用于一些简单的场景,或者需要直接操作 DOM 的情况。可能会减少一些状态管理的复杂性,但也失去了 React 组件对数据流的控制。
Container Components 容器组件和 Components 展示组件/UI组件:
容器组件主要负责数据逻辑和状态管理。包含业务逻辑,例如处理用户输入、发起网络请求等。通常是 class 组件,因为它们需要使用 state 和生命周期方法。
展示组件仅负责 UI 渲染,不处理数据逻辑。接收容器组件传递的数据和回调函数,并将其渲染为用户界面。可以是函数组件或纯函数组件。
通过将容器组件和展示组件分开,我们可以实现代码的分层和逻辑的解耦,使得代码更加清晰和易于维护。
todo
高阶组件(HOC):
高阶组件是将组件作为参数并生成另一个组件的函数。可以提高代码的复用性和灵活性。
高阶组件是装饰器模式在 React 中的实现。
应用例子:
对每个页面做权限控制,若是符合权限则正常渲染页面,不符合则渲染No Role Page. 希望在一个地方统一做权限控制处理
export const withAuth = (WrappedComponent) => {
const WithAuth = (props) => {
const { role } = props;
const currentRole = async () => {
return await gotRole();
};
const [isAdmin, setIsAdmin] = useState(false);
useEffect(() => {
if (role === currentRole) {
setIsAdmin(true);
}
}, [role]);
return isAdmin ? <WrappedComponent {...props} /> : <div>No Role</div>;
};
return WithAuth;
};