面试题
组件之间如何通讯?
- 父子组件通讯使用 props
- 自定义事件
- Redux
- 父组件向其下所有子孙组件传递信息使用 Context
- 例如:主题色、语言等
JSX 本质是什么?
- 通过 React.createElement 即 h 函数,返回 vnode
- 第一个参数,可能是组件,也可能是 html tag
- 组件名,首字母必须大写(React 规定)
Redux 单项数据流图示
setState 场景题
componentDidMount(){
// count 初始值为 0
this.setState({count: this.state.count +1})
console.log('1',this.state.count); // 0
this.setState({count: this.state.count +1})
console.log('1',this.state.count); // 0
// 同步
setTimeout(()=>{
this.setState({count: this.state.count +1})
console.log('3',this.state.count); // 2
})
setTimeout(()=>{
this.setState({count: this.state.count +1})
console.log('4',this.state.count); // 3
})
}
什么是纯函数
- 输入什么就返回什么
- 返回的新值,没有副作用(不会偷偷修改其他值)
- ⭐️ 重点是不可变值(例如:arr1 = arr.slice())
React组件的生命周期
单组件生命周期
- 页面初次渲染:constructor-->componentWillMount-->render-->componentDidMount(发送 ajax请求)
- 更新状态:shouldComponentUpdate(newProps,newState)-->componentWillUpdate-->render-->componentDidUpdate
父子组件生命周期
- 页面初次渲染:constructor-->componentWillMount-->render ----> son-constructor-->son-componentWillMount-->son-render-->son-componentDidMount -->componentDidMount
- 更新状态:father-shouldComponentUpdate--->father-componentWillUpdate--->father-render-->son-componentWillReceiveProps-->son-componentWillUpdate-->son-render--->son-componentDidUpdate--->father-componentDidUpdate**
注意
- shouldComponentUpdate 用于性能优化,需要配合 不可变值 一起使用。
- ajax 请求,应当在 componentDidMount 发送(此时 DOM 已经渲染完成)
- componentWillReceiveProps和shouldComponentUpdate区别:前者里面不能更改状态,后者可以
渲染列表数据,为什么使用 key?
- 必须使用 key,并且 key 值不能是 index 和 random
- diff 算法中通过 tag 和 key 来判断,是否是 sameNode
- 减少渲染次数,提升渲染性能
函数组件和 class 组件的区别
- 纯函数,输入 props,输出 JSX
- 没有实例,没有生命周期,没有 state
- 不能扩展其他方法
什么是受控组件?- 优先使用
表单的值受 state 控制,需要自行监听 onChange,更新 state。
import React, { Component } from 'react'
export default class FormDemo extends Component {
constructor(props) {
super(props)
this.state = {
name: '小辉',
info: '个人信息',
city: 'beijing',
flag: true,
gender: 'male'
}
}
onInputChange = (e) => {
this.setState({
name: e.target.value
})
}
render() {
// ⭐️ 受控组件
return (
<div>
<p>{this.state.name}</p>
{/* 用 htmlFor 代替 for */}
<label htmlFor='inputName'>姓名:</label>
<input id='inputName' value={this.state.name} onChange={this.onInputChange} />
</div>
)
}
}
什么是非受控组件?
状态 state 不受表单值的改变而改变。
import React, { Component } from 'react'
export default class UncontrolledDemo extends Component {
constructor(props){
super(props)
this.state = {
name:'小辉',
flag:true
}
this.nameInputRef = React.createRef(); // ⭐️ 1.创建 ref, 返回的是一个对象
}
alertName = () =>{
const elem = this.nameInputRef.current; // 通过 ref 获取 DOM 节点,从中取最新值
alert(elem.value) // 这里拿到的值不是 this.state.name
}
render() {
// input defaultValue
return (
<div>
{/* 使用 defaultValue 而不是 value,⭐️ 2.使用 ref */}
<input defaultValue={this.state.name} ref={this.nameInputRef}/>
{/* state 并不会随着改变 */}
<span>state.name:{this.state.name}</span>
<br/>
{/* ⭐️ 3. alertName */}
<button onClick={this.alertName}>alert name</button>
</div>
)
}
}
使用场景
- 必须手动操作 DOM 元素,setState 实现不了
- 文件上传
<input type="file"/>
- 类组件中,通过React.createRef(),创建一个 ref 对象;通过 ref 将创建的对象绑定到 input 标签上。
import React, { Component } from 'react' export default class UncontrolledDemo extends Component { constructor(props) { super(props) this.state = { name: '小辉', flag: true } this.fileInputRef = React.createRef(); // ⭐️ 1-1 创建 ref, 返回的是一个对象 } // ⭐️ 1-3 alertFile = () => { const elem = this.fileInputRef.current; // 通过 ref 获取 DOM 节点 alert(elem.files[0].name) } render() { // ⭐️ 1-2 file - 上传文件必须使用非受控组件 return ( <div> <input type="file" ref={this.fileInputRef} /> <button onClick={this.alertFile}>alert file</button> </div> ) } }
- 某些富文本编辑器,需要传入 DOM 元素
多个组件有公共逻辑,如何抽离?
- 高阶组件 HOC - 模式简单,但会增加组件层级
- HOC 是接收一个组件,返回一个新组件,类似于一个工厂(装饰器)
// 高阶组件不是一种功能,而是一种模式 const HOCFactory = (Component) =>{ class HOC extends React.Component { // 在此定义多个组件的公共逻辑 render(){ return <Component {...this.props}/> // 返回拼装的结果 } } return HOC } const EnhancedComponent1 = HOCFactory(WrappedComponent1); const EnhancedComponent2 = HOCFactory(WrappedComponent2);
- Render Props - 代码简洁,学习成本较高
// Render Props 的核心思想
// 通过一个函数将 class 组件的 state 作为 props 传递给纯函数组件
class Factory extends React.Component {
constructor(){
this.state = {
// state 即多个组件的公共逻辑的数据
}
}
// 修改 state
render(){
return <div>{this.props.render(this.state)}</div>
}
}
// 组件调用
const App = () =>(
<Factory render={
// render 是一个函数组件
(props) =><p>{props.a} {props.b} ...</p>
}/>
)
- mixin 已被 React 废弃
Redux 如何进行异步请求
- 使用异步 action,如 redux-thunk
react-router 如何配置懒加载
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom'
import React,{lazy,Suspense} from 'react'
const Home = lazy(()=>import('./routes/Home'));
const About = lazy(()=>import('./routes/About'))
const App = () =>(
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/about" component={Home} />
</Switch>
</Suspense>
</Router>
)
性能优化
PureComponent 有何区别
- PureComponent 实现了浅比较的 shouldComponentUpdate(只比较第一层),实现优化性能,但是需要结合 不可变值 使用。
性能优化的方式
- 渲染列表时,给
<li></li>
增加 key 值 - 自定义事件、DOM 事件及时销毁
- 合理使用异步组件
- 减少函数 bind this 的次数
- 合理使用 shouldComponentUpdate 和 memo
- 合理使用 Immutable.js
- webpack 层面的优化
- 前端通用的性能优化,如图片懒加载
- 使用 SSR
React 事件和 DOM 事件的区别
- React17 之前,所有事件挂载到 document 上,React17 以后,事件绑定到了 root 组件上。(有利于多个 React 版本并存,例如:微前端)
- event 不是原生的, 是 SyntheticEvent 合成事件对象
- dispatchEvent 机制
Vue 和 React 的区别
- 相同点:
- 都支持组件化
- 都是数据驱动视图
- 都使用 vdom 操作 DOM
- 不同点:
- React 使用 JSX 拥抱 JS,Vue 使用模版拥抱 html
- React 是函数式编程,Vue 是声明式编程(Vue 将需要的 data 内容变量声明好,页面修改值,内部进行监听,每一个值都是声明式的操作。React 是函数式的编程,每一次修改都是通过 setState(传入一个 state,返回一个 JSX)。)
- React 更多需要自力更生,Vue 把想要的都给你
React
React 原理
React 是一个用于构建用户界面的 JavaScript 库。它通过虚拟 DOM(Virtual DOM)和组件化的思想来提供高效、可重用和可维护的 UI 开发体验。下面是 React 的基本原理:
-
组件化开发:React 将用户界面分解为独立的、可复用的组件。每个组件负责管理自己的状态(State)和渲染输出。这样可以简化代码的编写和组织,并提高代码的可维护性。
-
虚拟 DOM(Virtual DOM):React 使用虚拟 DOM 来表示用户界面的状态。虚拟 DOM 是一个轻量级的 JavaScript 对象,它类似于对真实 DOM 树的内存中副本。当状态发生变化时,React 会使用算法比较新旧虚拟 DOM,并计算出最小化的 DOM 更新操作,然后将这些操作应用于真实 DOM,以达到高效更新界面的目的。
-
Diff 算法:React 的虚拟 DOM 引擎使用 Diff 算法来比较两个虚拟 DOM 树的差异。Diff 算法会在两个虚拟 DOM 树之间进行逐层比较,找出节点的差异,并为每个节点生成相应的 DOM 更新操作。这样可以最小化实际 DOM 的操作,提高性能。
-
单向数据流:React 使用单向数据流的思想来管理组件的状态更新。父组件可以通过 props 将数据传递给子组件,子组件无法直接修改父组件的数据,而是通过调用父组件提供的回调函数来通知父组件发生某个事件。这样可以确保状态的改变是可控和可追踪的。
-
生命周期方法:React 组件提供了一些生命周期方法,用于在组件的不同阶段执行特定的操作。例如,componentDidMount 在组件挂载后执行,componentWillUnmount 在组件卸载前执行。这些生命周期方法允许开发者在不同的时机处理组件的状态和行为。
-
状态管理:针对组件之间共享的状态,React 提供了一种称为 "上下文(Context)" 的机制,可以将状态数据传递给嵌套层级中的子组件。此外,开发者还可以使用第三方库(如 Redux、Mobx)来管理应用程序的全局状态。
通过以上原理,React 提供了一种高效、灵活且可扩展的方式来构建用户界面。它将关注点分离,将界面的描述和状态逻辑解耦,使得开发者可以专注于组件的开发和交互逻辑,提高开发效率和代码质量。
diff 算法
Diff 算法是 React 在进行虚拟 DOM 更新时使用的一种算法,用于比较两个虚拟 DOM 树之间的差异,并生成最小化的 DOM 更新操作。这样可以提高性能,减少不必要的 DOM 操作。
React Diff 算法的基本思想如下:
-
比较树的根节点:首先,React 会比较旧虚拟 DOM 树和新虚拟 DOM 树的根节点。如果根节点类型不同,React 将销毁旧节点,创建新节点并替换掉旧节点。
-
比较子节点:如果根节点类型相同,React 将逐层比较旧虚拟 DOM 树和新虚拟 DOM 树的子节点。
-
列表子节点的 Diff:对于列表类型的子节点,React 使用一种称为 "key"的特殊属性来进行优化。通过比较列表中的 key 值,React 可以快速判断哪些节点需要移动、增加或删除。
-
同级子节点的 Diff:对于同级的子节点,React 使用一种称为 "双指针" 的策略进行 Diff。它会使用两个指针分别在旧节点列表和新节点列表上移动,比较节点的类型和 key 值以确定操作类型(插入、移动、删除)。
-
递归进行 Diff:如果节点类型相同,React 将递归比较节点的子节点。这样可以找到更深层次的差异,并进行相应的 DOM 更新操作。
-
更新差异的节点:在完成 Diff 过程后,React 会根据比较结果生成最小化的 DOM 更新操作。这些操作将被应用于真实 DOM,以达到更新界面的目的。
React Diff 算法通过比较虚拟 DOM 树的差异,并进行逐层的优化比较,使得 DOM 更新的操作量最小化。这种优化方式可以提高性能,减少不必要的 DOM 操作和重新渲染,从而提高应用程序的响应速度和用户体验。
虚拟 DOM
虚拟 DOM(Virtual DOM)是 React 中的一个概念,它是 React 进行高效的 DOM 操作和更新的基础。
虚拟 DOM 是一个轻量级的 JavaScript 对象,它是对真实 DOM 树的一种抽象表示。通过使用虚拟 DOM,React 可以跟踪和管理界面的状态变化,并根据需要生成最小化的 DOM 更新操作。
以下是虚拟 DOM 的基本工作原理:
-
状态变化:当 React 组件的状态(状态数据)发生变化时,React 需要更新用户界面以反映这些变化。
-
生成虚拟 DOM:React 使用组件的渲染函数(或称为 render 方法)生成一个新的虚拟 DOM 树。这个树结构描述了新的界面状态。
-
Diff 算法:React 借助 Diff 算法,比较新旧虚拟 DOM 树之间的差异。Diff 算法将比较节点的类型、属性和子节点,并找出需要进行 DOM 更新操作的节点。
-
计算 DOM 更新操作:通过 Diff 算法的比较结果,React 计算出最小化的 DOM 更新操作。这些操作描述了如何在真实 DOM 上更新节点和属性。
-
应用 DOM 更新操作:最后,React 将计算出的 DOM 更新操作应用于实际的 DOM 树。只有那些需要更新的节点才会被实际更新,而不是更新整个界面。
通过使用虚拟 DOM,React 提供了一种高效的方式来更新用户界面。相比直接操作真实 DOM,虚拟 DOM 在进行比较和更新时具有更高的性能,因为它避免了直接的 DOM 操作和重绘。React 通过对比虚拟 DOM 树之间的差异,以最小的操作来更新实际的 DOM,从而减少了不必要的计算和渲染开销。
虚拟 DOM 还具有其他优点,例如可跨平台使用(可以用于浏览器和 React Native 等环境),便于进行测试和调试,以及提供了更灵活的编程模型等。
React-router
React-router 原理
React Router 是一个基于 React 的路由库,它的实现原理主要依赖于浏览器的 History API 和 React 的组件化特性。以下是 React Router 的主要实现原理:
-
- History API :React Router 使用浏览器的 History API(如:pushState、replaceState、popState事件)来管理浏览器的历史记录。当用户点击链接或者进行编程式导航时,React Router 会调用相应的 History API 来改变浏览器的地址栏和历史记录。
-
- 组件化:React Router 将路由功能封装成了一系列 React 组件(如:BrowserRouter、Route、Switch、 Link等)。这些组件可以像普通的 React 组件一样组合使用,从而实现灵活的路由配置和渲染。
-
- 监听地址变化:React Router 会监听浏览器地址栏的变化(包括用户点击链接、前进后退按钮、编程式导航等)当地址发生变化时,React Router 会根据当前的地址和路由配置来确定哪些组件需要渲染,然后触发 React 的重新渲染。
-
- React Router 使用 React 的 Context API 来在组件树中共享路由相关的信息,例如当前的地址、历史对象等。这样,路由组件和链接组件可以方便地访问这些信息,从而实现导航和渲染的功能。
综上所述:,React Router 的实现原理主要依赖于浏览器的 History API 和 React 的组件化特性。通过将路由功能封装成一系列组件,并利用 Context API 共享路由信息,React Router 能够实现灵活且易于使用的路由管理。
query 传参 和 params 传参的区别
在 React 路由器(React Router)中,有两种常用的方式来传递参数:query 和 params,它们在传递方式和获取方式上有所不同。Query 参数使用 URL 参数形式传递,可以通过 useLocation 钩子函数和解析库来获取;而 Params 参数直接嵌入在 URL 路径中,可以通过 useParams 钩子函数来获取。
- Query 参数在 React 路由器中使用 query 来传递参数。Query 参数是通过 URL 参数的形式传递的,通常出现在 ? 后面,参数之间使用 & 分隔。例如,对于以下 URL:example.com/search?quer… 和 category 就是 Query 参数。
-
在 React 路由器中,可以通过 useLocation 钩子函数或 location 对象的 search 属性来获取 Query 参数。可以使用解析库(如 query-string 或 URLSearchParams)来解析和处理 Query 参数。
import { useLocation } from 'react-router-dom'; function MyComponent() { const location = useLocation(); const searchParams = new URLSearchParams(location.search); const queryValue = searchParams.get('query'); const categoryValue = searchParams.get('category'); // 其他逻辑... return ( // 渲染你的组件 ); }
-
- Params 参数在 React 路由器中使用 params 来传递参数。Params 参数是直接嵌入在 URL 路径中的,通常用于标识唯一资源。在路由配置中,可以使用占位符(如 :id)指定 Params 参数。例如,对于以下 URL:example.com/users/123/p… 就是 Params 参数。
- 在 React 路由器中,可以通过 useParams 钩子函数来获取 Params 参数。
function MyComponent() { const { id } = useParams(); // 其他逻辑... return ( // 渲染你的组件 ); }
- 需要注意的是,在路由配置中,需要使用 :paramName 来指定 Params 参数。例如
<Route path="/users/:id" component={UserProfile} />
在以上示例中,将匹配类似 /users/123 这样的路径,并将 123 作为 Params 参数传递给 UserProfile 组件。
- 在 React 路由器中,可以通过 useParams 钩子函数来获取 Params 参数。
Redux
Redux 原理
Redux 是一个基于 JavaScript 的状态管理库,它遵循一种特定的架构模式,即 Flux 架构模式。Redux 的主要原理包括:
-
- 单一的数据源(Single Source of Truth):Redux 应用程序中的所有状态数据都存储在一个称为 "Store" 的单一对象中。这个对象是只读的,唯一改变它的方法是通过触发一个 "Action"。
-
- 状态是只读的(State is Read-Only):Redux 中的状态是只读的,意味着您不能直接修改它。要改变状态,您需要触发一个 Action,Action 是一个描述状态变化的普通 JavaScript 对象。
-
- 通过纯函数来执行状态更改(Changes are made with Pure Functions):为了描述状态的变化,您需要编写一个纯函数,这个函数被称为 "Reducer"。Reducer 接收当前状态和要执行的 Action,并返回一个新的状态对象。
-
- 使用订阅/发布模式进行状态更新(Updates are made with Subscription/Publish pattern):当状态发生变化时,Redux 会通知应用程序中的所有订阅者。组件可以订阅 Redux Store,并在状态更改时接收通知。
-
- 使用中间件来处理异步操作(Middleware for handling asynchronous operations):Redux 支持中间件来处理异步操作,例如发起异步请求,然后根据响应更新状态。中间件可以拦截 Action,并在达到 Reducer 之前执行其他逻辑。
通过这些原理,Redux 提供了一个可预测、可维护的状态管理解决方案,帮助开发者构建可扩展的应用程序。在 Redux 中,状态管理需要遵循一定的模式和规范,以提高代码的可读性和可维护性。
Redux 的使用
Redux 是一个 JavaScript 的状态管理库,用于管理应用程序的状态。它可以与任何 JavaScript 应用程序一起使用,包括 React、Angular、Vue 等。Redux 的核心概念包括:
-
1. Store(仓库):Store 是 Redux 的核心对象,它保存了应用程序的整个状态树。通过调用 createStore(reducer, [preloadedState], [enhancer]) 方法可以创建一个 Store。
-
2. Action(动作):Action 是一个描述状态变化的纯 JavaScript 对象。它必须包含一个
type
属性来指示要执行的操作,并可以包含其他任意属性来传递额外的数据。 -
3. Reducer(处理器):Reducer 是一个纯函数,它接收一个旧的状态和一个 Action,并返回一个新的状态。Reducer 定义了应用程序状态的变化方式。
-
4. Dispatch(派发):Dispatch 是一个用于发送 Action 的函数。当你想要改变应用程序的状态时,你需要使用
store.dispatch(action)
来分发一个 Action。 -
5. Subscribe(订阅):Subscribe 可以让你注册一个回调函数,用于在应用程序的状态发生变化时触发更新。
-
6. Middleware(中间件):Redux 允许使用中间件来扩展 Store 的功能。中间件可以拦截和处理 Action,并在到达 Reducer 之前执行额外的逻辑。例如,用于处理异步操作的 Redux Thunk 或 Redux Saga。
Redux 的工作流程如下:
- 通过调用
createStore(reducer, [preloadedState], [enhancer])
方法创建一个 Store。 - 定义一个或多个 Reducer 函数,每个 Reducer 函数处理应用程序的一部分状态。
- 在组件中使用
store.dispatch(action)
方法来分发 Action,以触发状态变化。 - Store 调用 Reducer 函数来生成新的状态。
- Store 更新状态后,通知订阅者,以便重新渲染组件。
- 组件接收到新的状态,并相应地更新视图。
- 重复以上步骤,实现状态的管理和更新。
Redux 提供了一种可预测性的状态管理方式,使得应用程序的状态变化变得可控和可追踪,减少了状态管理的复杂性,并提高了代码的可维护性。
Redux-Thunk 的使用
Redux Thunk 是一个用于处理异步逻辑的中间件,它可以让你在 Redux 应用程序中编写具有副作用(如异步网络请求)的 Action Creator。它的主要作用是延迟 Action 的执行,允许你在 Action Creator 中返回一个函数而不是一个普通的 Action 对象。
以下是 Redux Thunk 的基本使用步骤:
- 安装 Redux Thunk:首先,使用 npm 或 yarn 安装 redux-thunk。
npm install redux-thunk
# 或
yarn add redux-thunk
- 应用 Redux Thunk 中间件:在创建 Redux Store 时,使用 applyMiddleware 方法将 Redux Thunk 添加为中间件。
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const store = createStore(rootReducer, applyMiddleware(thunk));
- 创建异步 Action Creator:创建一个返回函数的 Action Creator,而不是返回一个普通的 Action 对象。这个函数接收 dispatch 和 getState 作为参数,可以在函数体内执行异步操作,最后根据需要 dispatch 一个或多个 Action 对象。
const fetchPosts = () => {
return (dispatch, getState) => {
// 异步请求数据
fetch('https://api.example.com/posts')
.then(response => response.json())
.then(data => {
// 请求成功后,根据需要 dispatch 相应的 Action
dispatch({ type: 'FETCH_POSTS_SUCCESS', payload: data });
})
.catch(error => {
// 请求失败后,根据需要 dispatch 相应的 Action
dispatch({ type: 'FETCH_POSTS_ERROR', payload: error });
});
};
};
在上面的示例中,fetchPosts 是一个异步的 Action Creator,它返回一个函数。在这个函数中,我们可以执行异步操作(如网络请求),请求成功后 dispatch FETCH_POSTS_SUCCESS Action,请求失败后 dispatch FETCH_POSTS_ERROR Action。
- 分发异步 Action:使用 store.dispatch 方法来分发异步 Action。
store.dispatch(fetchPosts());
上面的代码将触发 fetchPosts 异步 Action Creator,开始执行异步操作。
Redux Thunk 允许您在 Action Creator 中处理异步逻辑,延迟 Action 的执行,以便在异步操作完成后再 dispatch 相应的 Action。这样可以更好地管理异步行为,并使 Redux 与异步操作无缝集成。
React Redux 原理
React Redux 是用于在 React 应用中进行状态管理的官方库。它结合了 React 组件和 Redux 状态管理,提供了一种可预测、可扩展和可维护的状态管理方案。
下面是 React Redux 的基本原理:
-
Redux 的工作原理:React Redux 首先建立在 Redux 的核心概念之上。Redux 使用单一的全局状态树来管理应用程序的状态。通过定义动作(actions)和纯函数的方式,Redux 实现了一种可预测的状态变更流程。
-
提供器组件 Provider:React Redux 提供了一个名为
Provider
的顶层组件。该组件接收 Redux 的 store 作为 prop,并将其传递给子组件树中的所有其他组件。 -
连接函数 connect:React Redux 提供了一个名为
connect
的高阶函数。connect
函数接受两个参数:mapStateToProps
和mapDispatchToProps
。它返回一个通过连接(在组件层级上)Redux store 的组件。 -
mapStateToProps:
mapStateToProps
是一个函数,它将 Redux store 中的状态映射到组件的 props。这样,组件就可以通过访问props
来获取所需的状态数据。 -
mapDispatchToProps:
mapDispatchToProps
是一个函数或对象,它将动作创建函数映射到组件的 props。这样,组件就可以在需要时通过调用这些映射函数来分发动作。 -
容器组件和展示组件:通过使用
connect
函数,我们可以将组件分成容器组件和展示组件。容器组件通过连接 Redux store 和映射函数来处理状态和动作的逻辑。展示组件则负责展示数据和与用户进行交互。 -
通过 props 访问状态和分发动作:通过连接和映射函数,React Redux 确保容器组件可以通过 props 访问所需的状态数据和分发动作。当状态变化时,容器组件会自动更新展示组件,以反映最新的状态。
通过以上原理,React Redux 提供了一种结构化、可维护且可预测的状态管理方式。它通过将 Redux store 与组件树进行连接,并利用映射函数将状态数据和动作分发函数注入到组件中,使得组件可以轻松地访问和管理应用程序的状态。这种可预测性和单向数据流的状态管理模式有助于开发大型、复杂的 React 应用程序时保持代码的可维护性和可扩展性。
Mobx 的使用
Mobx 是一个简单、可扩展且高效的状态管理库,它可以与 React 或其他 JavaScript 框架一起使用。下面是使用 Mobx 的基本步骤:
- 安装 Mobx:使用 npm 或 yarn 安装 Mobx 和 Mobx React。
npm install mobx mobx-react
# 或
yarn add mobx mobx-react
- 创建可观察状态(Observable):使用
observable
函数创建可观察的状态。这些状态将被 Mobx 追踪和自动更新。
import { observable } from 'mobx';
const counterStore = observable({
count: 0,
});
在上述示例中,counterStore
对象是一个可观察的状态,其中的 count
字段表示计数器的值。
- 使用可观察状态:在组件或其他代码中使用可观察状态。可以通过直接读取和修改可观察状态来进行状态管理。
import { observer } from 'mobx-react';
const Counter = observer(() => {
const increment = () => {
counterStore.count++;
};
const decrement = () => {
counterStore.count--;
};
return (
<div>
<button onClick={decrement}>-</button>
<span>{counterStore.count}</span>
<button onClick={increment}>+</button>
</div>
);
});
在上述示例中,我们使用 observer
函数将 Counter
组件包裹起来,使其成为一个可观察组件。当 count
字段发生变化时,组件将自动重新渲染。
- 使用计算属性(Computed Property):Mobx 还支持计算属性,它是根据其他可观察状态或计算属性派生出来的值。
import { computed } from 'mobx';
const counterStore = observable({
count: 0,
get doubledCount() {
return this.count * 2;
},
});
console.log(counterStore.doubledCount); // 输出当前计数的两倍
在上述示例中,我们使用 computed
函数创建了一个计算属性 doubledCount
,它返回 count
值的两倍。
这些是使用 Mobx 的基本步骤,如果需要更复杂的状态管理,Mobx 还提供了更多的功能,比如使用动作(Actions)来修改状态、使用观察者(Reactions)自动响应状态变化等。通过 Mobx,您可以轻松地进行状态管理,并实现响应式的用户界面。请注意,Mobx 不同于 Redux,它提供了一种不同的状态管理方式,可以根据您的具体需求选择合适的工具。