>  기사  >  웹 프론트엔드  >  Redux와 Mobx의 선택 예시에 대한 자세한 설명

Redux와 Mobx의 선택 예시에 대한 자세한 설명

小云云
小云云원래의
2018-02-09 13:17:281403검색

Redux와 Mobx는 모두 현재 인기 있는 데이터 흐름 모델입니다. 커뮤니티에서는 Redux를 대체하기 위해 무엇을 선택해야 할지 자연스럽게 혼란스러워하는 것 같습니다. 개발자는 어떤 솔루션을 선택해야 할지 확신하지 못합니다. 이 문제는 Redux와 Mobx에만 국한되지 않습니다. 선택의 여지가 있을 때마다 사람들은 문제를 해결하는 가장 좋은 방법이 무엇인지 궁금해합니다. 내가 지금 쓰고 있는 것은 두 상태 관리 라이브러리 Redux와 Mobx 사이의 혼란을 해결하는 것입니다.

대부분의 기사는 Mobx와 Redux의 사용법을 소개하기 위해 React를 사용합니다. 그러나 대부분의 경우 React를 Angular, Vue 또는 다른 것으로 대체할 수 있습니다.

2016년 초에 저는 React + Redux를 사용하여 상당히 큰 애플리케이션을 작성했습니다. Mobx가 Redux의 대안으로 사용될 수 있다는 사실을 발견했을 때 저는 Redux에서 Mobx로 애플리케이션을 리팩터링하는 데 시간을 투자했습니다. 이제 매우 편안하게 사용하고 사용법을 설명할 수 있습니다.

이 기사에서는 무엇을 이야기할까요? 그렇게 긴 기사를 읽을 계획이 없다면(TLDR: 너무 길어서 읽지 않았습니다(이 링크를 보려면 자신의 사다리를 가져오세요)). 목차를 보면 됩니다. 하지만 더 자세한 내용을 알려드리고 싶습니다. 먼저 상태 관리 라이브러리가 우리를 위해 해결하는 문제가 무엇인지 간략하게 검토하고 싶습니다. 결국, React를 작성할 때 setState()만 사용하거나 다른 SPA 프레임워크를 작성할 때 setState() 및 유사한 메소드를 사용하면 동일한 작업을 수행할 수 있습니다. 둘째, 이들 간의 유사점과 차이점에 대해 간략히 말씀드리겠습니다. 셋째, React 생태계의 초보자들에게 React의 상태 관리를 배우는 방법을 보여드리겠습니다. 친절한 알림: Mobx 및 Redux를 시작하기 전에 먼저 setState()를 사용하세요. 마지막으로, Mobx 또는 Redux를 사용하는 애플리케이션이 이미 있는 경우 이러한 상태 관리 라이브러리 중 하나에서 다른 라이브러리로 리팩터링하는 방법에 대해 더 자세히 설명하겠습니다.

목차

우리가 해결하려는 문제는 무엇인가요?

Mobx와 Redux의 차이점은 무엇인가요?

React 상태 관리 학습 곡선

다른 상태 관리 솔루션을 사용해 볼까요?

최종 생각

우리가 해결하려는 문제는 무엇인가요?

모든 사람은 자신의 애플리케이션에서 상태 관리를 사용하고 싶어합니다. 하지만 그것이 우리에게 어떤 문제를 해결해 주나요? 많은 사람들이 소규모 애플리케이션을 시작할 때 상태 관리 라이브러리를 도입했습니다. 다들 Mobx와 Redux에 대해 이야기하고 있죠? 그러나 대부분의 애플리케이션은 처음에는 대규모 상태 관리가 필요하지 않습니다. Mobx 및 Redux와 같은 라이브러리가 해결해야 하는 문제를 이러한 사람들이 경험할 수 없기 때문에 이는 심지어 위험할 수도 있습니다.

현재 상황은 구성 요소를 사용하여 프런트 엔드 애플리케이션을 구축하는 것입니다. 구성 요소에는 자체 내부 상태가 있습니다. 예를 들어 React에서는 위에서 언급한 로컬 상태를 this.state 및 setState()를 사용하여 처리합니다. 그러나 로컬 상태의 상태 관리는 다음과 같은 이유로 인해 비대해진 애플리케이션에서 빠르게 혼란스러워질 수 있습니다.

한 구성 요소는 다른 구성 요소와 상태를 공유해야 합니다.

한 구성 요소는 다른 구성 요소의 상태를

어느 정도 변경해야 합니다. 신청 상태를 추론하는 것이 점점 더 어려워질 것입니다. 구성 요소 수준에서 서로의 상태를 수정하는 많은 상태 개체로 인해 혼란스러운 응용 프로그램이 됩니다. 대부분의 경우 상태 개체 및 상태 수정은 일부 구성 요소에 바인딩될 필요가 없습니다. 상태를 승격하면 구성 요소 트리를 통해 사용할 수 있습니다.

그래서 해결책은 Mobx나 Redux와 같은 상태 관리 라이브러리를 도입하는 것입니다. 상태를 저장하고, 상태를 수정하고, 어딘가에 상태를 업데이트하는 도구를 제공합니다. 한 곳에서 상태를 가져오고, 한 곳에서 수정하고, 한 곳에서 업데이트를 받을 수 있습니다. 이는 단일 데이터 소스의 원칙을 따릅니다. 이렇게 하면 상태 값과 상태 수정이 구성 요소와 분리되어 있기 때문에 더 쉽게 추론할 수 있습니다.

Redux 및 Mobx와 같은 상태 관리 라이브러리에는 일반적으로 React에서 사용되는 React-redux 및 mobx-react와 같은 도구가 함께 제공되어 구성 요소가 상태를 얻을 수 있습니다. 일반적으로 이러한 구성 요소를 컨테이너 구성 요소, 더 정확하게는 연결 구성 요소라고 합니다. 구성 요소를 연결된 구성 요소로 업그레이드하는 한 구성 요소 계층 구조 어디에서나 상태를 가져오고 변경할 수 있습니다.

Mobx와 Redux의 차이점은 무엇인가요?

Redux와 Mobx의 차이점을 살펴보기 전에 둘 사이의 유사점에 대해 이야기하고 싶습니다.

두 라이브러리 모두 JavaScript 애플리케이션의 상태를 관리하는 데 사용됩니다. React와 함께 번들로 제공될 필요는 없으며 AngularJ 및 VueJ와 같은 다른 라이브러리와 함께 사용할 수도 있습니다. 그러나 그들은 React의 아이디어와 매우 잘 통합됩니다.

상태 관리 솔루션 중 하나를 선택하면 그것에 얽매이는 느낌이 들지 않을 것입니다. 언제든지 다른 솔루션으로 전환할 수 있기 때문입니다. Mobx에서 Redux로 전환하거나 Redux에서 Mobx로 전환할 수 있습니다. 아래에서 이 작업을 수행하는 방법을 보여 드리겠습니다.

Dan Abramov의 Redux는 Flux 아키텍처에서 파생되었습니다. Flux와 달리 Redux는 상태를 저장하기 위해 여러 저장소 대신 단일 저장소를 사용합니다. 또한 상태를 수정하기 위해 디스패처 대신 순수 함수를 사용합니다. 이 내용에 속아 넘어가세요.

Redux는 FP(함수형 프로그래밍) 원칙의 영향을 받습니다. FP는 JavaScript에서 사용할 수 있지만 많은 사람들이 Java와 같은 객체 지향 언어에 대한 배경 지식을 가지고 있습니다. 처음에는 함수형 프로그래밍의 원칙에 적응하는 데 어려움을 겪습니다. 이것이 Mobx가 초보자에게 더 간단할 수 있는 이유입니다.

Redux는 FP를 수용하므로 순수 기능을 사용합니다. 입력을 받아 출력을 반환하며 다른 종속성이 없는 순수 함수입니다. 순수 함수는 동일한 입력에 대해 항상 동일한 출력을 가지며 부작용이 없습니다.


(state, action) => newState

Redux 상태는 변경할 수 없으므로 원래 상태를 수정하는 대신 항상 새 상태를 반환해야 합니다. 상태 수정이나 개체 참조를 기반으로 한 변경을 수행해서는 안 됩니다.


// don't do this in Redux, because it mutates the array
function addAuthor(state, action) {
 return state.authors.push(action.author);
}
// stay immutable and always return a new object
function addAuthor(state, action) {
 return [ ...state.authors, action.author ];
}

마지막으로 Redux의 관용구에서는 상태 형식이 데이터베이스처럼 표준화되어 있습니다. 엔터티는 ID로만 서로를 참조하는데 이는 모범 사례입니다. 모든 사람이 이 작업을 수행하는 것은 아니지만 Normalizr을 사용하여 상태를 정규화할 수도 있습니다. 정규화된 상태를 사용하면 단순 상태를 유지하고 엔터티를 단일 데이터 소스로 유지할 수 있습니다.


{
 post: {
 id: 'a',
 authorId: 'b',
 ...
 },
 author: {
 id: 'b',
 postIds: ['a', ...],
 ...
 }
}

Michel Weststrate의 Mobx는 객체 지향 프로그래밍과 반응형 프로그래밍의 영향을 받았습니다. 상태를 관찰 가능한 객체로 래핑하므로 상태는 Observable의 모든 기능을 갖습니다. 상태 데이터에는 일반 setter와 getter만 있을 수 있지만 Observable을 사용하면 데이터가 변경될 때 업데이트된 값을 얻을 수 있습니다.

Mobx의 상태는 변경 가능하므로 상태를 직접 수정합니다.


function addAuthor(author) {
 this.authors.push(author);
}

또한 상태 엔터티는 서로 관련되도록 중첩된 데이터 구조를 유지합니다. 상태를 표준화할 필요가 없으며 대신 중첩된 상태로 유지하세요.


{
 post: {
 id: 'a',
 ...
 author: {
 id: 'b',
 ...
 }
 }
}

단일 저장소 vs. 다중 저장소

Redux에서는 모든 상태를 전역 저장소에 넣습니다. 이 저장소 개체는 단일 데이터 소스입니다. 반면에 여러 리듀서를 사용하면 불변 상태를 수정할 수 있습니다.

Mobx는 반면에 여러 매장을 사용합니다. Redux 감속기와 유사하게 기술 수준이나 도메인에서 분할하고 정복할 수 있습니다. 도메인 엔터티를 다른 저장소에 저장하면서도 보기에서 상태에 대한 제어를 계속 유지하고 싶을 수도 있습니다. 결국 애플리케이션이 합리적으로 보이도록 상태를 구성합니다.

기술적으로 Redux에서는 여러 스토어를 사용할 수도 있습니다. 어느 누구도 매장 하나만 이용하라고 강요하지 않습니다. 그러나 이는 Redux의 권장 사용법이 아닙니다. 이는 모범 사례에 어긋나기 때문입니다. Redux에서는 단일 저장소가 리듀서의 글로벌 이벤트를 통해 업데이트에 응답합니다.

사용 방법은?

Redux 사용법을 배우려면 먼저 전역 상태에 사용자 배열을 추가해야 합니다. 새로운 객체를 반환하기 위해 객체 확산 연산자를 사용하고 있다는 것을 알 수 있습니다. ES6(원래는 ES5, 실제로는 ES6)의 불변 객체에 대해 작업을 수행하기 위해 Object.sign()을 사용할 수도 있습니다.


const initialState = {
 users: [
 {
 name: 'Dan'
 },
 {
 name: 'Michel'
 }
 ]
};
// reducer
function users(state = initialState, action) {
 switch (action.type) {
 case 'USER_ADD':
 return { ...state, users: [ ...state.users, action.user ] };
 default:
 return state;
 }
}
// action
{ type: 'USER_ADD', user: user };

전역 상태에 새 사용자를 추가하려면 dispatch({ type: 'USER_ADD', user: user });를 사용해야 합니다.

Mobx에서 저장소는 하나의 하위 상태만 관리하지만(Redux에서 하위 상태를 관리하는 리듀서와 마찬가지로) 상태를 직접 수정할 수 있습니다.

@observable을 사용하면 상태 변화를 관찰할 수 있습니다.


class UserStore {
 @observable users = [
 {
 name: 'Dan'
 },
 {
 name: 'Michel'
 }
 ];
}

이제 스토어 인스턴스 메소드 userStore.users.push(user);를 호출할 수 있습니다. 상태를 수정하기 위해 작업을 사용하는 것이 더 명시적이지만 이는 모범 사례입니다.


class UserStore {
 @observable users = [
 {
 name: 'Dan'
 },
 {
 name: 'Michel'
 }
 ];
 @action addUser = (user) => {
 this.users.push(user);
 }
}

Mobx에서는 useStrict()를 추가하여 액션을 강제로 사용할 수 있습니다. 이제 상점 인스턴스에서 userStore.addUser(user); 메소드를 호출하여 상태를 수정할 수 있습니다.

Redux와 Mobx에서 상태를 업데이트하는 방법을 살펴보았습니다. Redux의 상태는 읽기 전용이며, Mobx에서는 상태를 직접 읽고 쓸 수 있습니다. 명시적 작업을 사용하려면 Strict( )를 사용할 수 있습니다.

React 상태 관리 학습 곡선

React 애플리케이션은 Redux와 Mobx를 광범위하게 사용합니다. 그러나 이들은 독립적인 상태 관리 라이브러리이며 React를 제외한 모든 곳에서 사용할 수 있습니다. 상호 운용성 라이브러리를 사용하면 React 구성 요소를 쉽게 연결할 수 있습니다. Redux + React의 경우 반응-redux, MobX + React의 경우 mobx-react. 나중에 React 컴포넌트 트리에서 어떻게 사용되는지 설명하겠습니다.

최근 토론에서 사람들은 Redux의 학습 곡선에 대해 토론했습니다. 이는 일반적으로 다음 시나리오에서 발생합니다. 상태 관리를 위해 Redux를 사용하려는 React 초보자. 대부분의 사람들은 React와 Redux가 그 자체로 높은 학습 곡선을 가지고 있고 둘을 결합하면 감당하기 어려울 수 있다고 생각합니다. 대안은 초보자에게 더 적합한 Mobx입니다.

然而,我会建议 React 的初学者一个学习状态管理的新方法。先学习React 组件内部的状态管理功能。在 React 应用,你首先会学到生命周期方法,而且你会用 setState() 和 this.state 解决本地的状态管理。我非常推荐上面的学习路径。不然你会在 React 的生态中迷失。在这条学习路径的最后,你会认识到组件内部管理状态难度越来越大。毕竟那是 The Road to learn React 书里如何教授 React 状态管理的方法。

现在我们重点讨论 Redux 和 Mobx 为我们解决了什么问题?它俩都提供了在组件外部管理应用状态的方法。state 与组件相互解耦,组件可以读取 state ,修改 state ,有新 state 时更新。这个 state 是单一数据源。

现在你需要选择其中一个状态管理库。这肯定是要第一时间解决的问题。此外,在开发过相当大的应用之后,你应该能很自如使用 React 。

初学者用 Redux 还是 Mobx ?

一旦你对 React 组件和它内部的状态管理熟悉了,你就能选择出一个状态管理库来解决你的问题。在我两个库都用过后,我想说 Mobx 更适合初学者。我们刚才已经看到 Mobx 只要更少的代码,甚至它可以用一些我们现在还不知道的魔法注解。
用 Mobx 你不需要熟悉函数式编程。像“不可变”之类的术语对你可能依然陌生。函数式编程是不断上升的范式,但对于大部分 JavaScript 开发者来说是新奇的。虽然它有清晰的趋势,但并非所有人都有函数式编程的背景,有面向对象背景的开发者可能会更加容易适应 Mobx 的原则。

   注:Mobx 可以很好的在 React 内部组件状态管理中代替 setState,我还是建议继续使用 setState() 管理内部状态。但链接文章很清楚的说明了在 React 中用 Mobx 完成内部状态管理是很容易的。                                                                      

规模持续增长的应用

在 Mobx 中你改变注解过的对象,组件就会更新。Mobx 比 Redux 使用了更多的内部魔法实现,因此在刚开始的时候只要更少的代码。有 Angular 背景的会觉得跟双向绑定很像。你在一个地方保存 state ,通过注解观察 state ,一旦 state 修改组件会自动的更新。

Mobx 允许直接在组件树上直接修改 state 。


// component
<button onClick={() => store.users.push(user)} />

更好的方式是用 store 的 @action 。


// component
<button onClick={() => store.addUser(user)} />
// store
@action addUser = (user) => {
 this.users.push(user);
}

用 actions 修改 state 更加明确。上面也提到过,有个小功能可以强制的使用 actions 修改 state 。


// root file
import { useStrict } from &#39;mobx&#39;;
useStrict(true);

这样的话第一个例子中直接修改 store 中的 state 就不再起作用了。前面的例子展示了怎样拥抱 Mobx 的最佳实践。此外,一旦你只用 actions ,你就已经使用了 Redux 的约束。

在快速启动一个项目时,我会推荐使用 Mobx ,一旦应用开始变得越来越大,越来越多的人开发时,遵循最佳实践就很有意义,如使用明确的 actions 。这是拥抱 Redux 的约束:你永远不能直接修改 state ,只能使用 actions 。

迁移到 Redux

一旦应用开始变得越来越大,越来越多的人开发时,你应该考虑使用 Redux 。它本身强制使用明确的 actions 修改 state 。action 有 type 和 payload 参数,reducer 可以用来修改 state 。这样的话,一个团队里的开发人员可以很简单的推断 state 的修改。


// reducer
(state, action) => newState

Redux 提供状态管理的整个架构,并有清晰的约束规则。这是 Redux 的成功故事。

另一个 Redux 的优势是在服务端使用。因为我们使用的是纯 JavaScript ,它可以在网络上传输 state 。序列化和反序列化一个 state 对象是直接可用的。当然 Mobx 也是一样可以的。

Mobx 是无主张的,但你可以通过 useStrict() 像 Redux 一样使用清晰的约束规则。这就是我为什么没说你不能在扩张的应用中使用 Mobx ,但 Redux 是有明确的使用方式的。而 Mobx 甚至在文档中说:“ Mobx 不会告诉你如何组织代码,哪里该存储 state 或 怎么处理事件。”所以开发团队首先要确定 state 的管理架构。

状态管理的学习曲线并不是很陡峭。我们总结下建议:React 初学者首先学习恰当的使用 setState() 和 this.state 。一段时间之后你将会意识到在 React 应用中仅仅使用 setState() 管理状态的问题。当你寻找解决方案时,你会在状态管理库 Mobx 或 Redux 的选择上犹豫。应该选哪个呢?由于 Mobx 是无主张的,使用上可以和 setState() 类似,我建议在小项目中尝试。一旦应用开始变得越来越大,越来越多的人开发时,你应该考虑在 Mobx 上实行更多的限制条件或尝试使用 Redux 。我使用两个库都很享受。即使你最后两个都没使用,了解到状态管理的另一种方式也是有意义的。

尝试另一个状态管理方案?

你可能已经使用了其中一个状态管理方案,但是想考虑另一个?你可以比较现实中的 Mobx 和 Redux 应用。我把所有的文件修改都提交到了一个Pull Request 。在这个 PR 里,项目从 Redux 重构成了 Mobx ,反之亦然,你可以自己实现。我不认为有必要和 Redux 或 Mobx 耦合,因为大部分的改变是和其他任何东西解耦的。

你主要需要将 Redux 的 Actions、Action Creator、 Action Types、Reducer、Global Store 替换成 Mobx 的 Stores 。另外将和 React 组件连接的接口 react-redux 换成 mobx-react 。presenter + container pattern 依然可以执行。你仅仅还要重构容器组件。在 Mobx 中可以使用 inject 获得 store 依赖。然后 store 可以传递 substate 和 actions 给组件。Mobx 的 observer 确保组件在 store 中 observable 的属性变化时更新。


import { observer, inject } from &#39;mobx-react&#39;;
...
const UserProfileContainer = inject(
 &#39;userStore&#39;
)(observer(({
 id,
 userStore,
}) => {
 return (
 <UserProfile
 user={userStore.getUser(id)}
 onUpdateUser={userStore.updateUser}
 />
 );
}));

Redux 的话,你使用 mapStateToProps 和 mapDispatchToProps 传递 substate 和 actions 给组件。


import { connect } from &#39;react-redux&#39;;
import { bindActionCreators } from &#39;redux&#39;;
...
function mapStateToProps(state, props) {
 const { id } = props;
 const user = state.users[id];
 return {
 user,
 };
}
function mapDispatchToProps(dispatch) {
 return {
 onUpdateUser: bindActionCreators(actions.updateUser, dispatch),
 };
}
const UserProfileContainer = connect(mapStateToProps, mapDispatchToProps)(UserProfile);

这有一篇怎样将 Redux 重构为 Mobx指南。但就像我上面说过的,反过来一样也是可以的。一旦你选择了一个状态管理库,你会知道那并没有什么限制。它们基本上是和你的应用解耦的,所以是可以替换的。

最后思考

每当我看 Redux vs Mobx 争论下的评论时,总会有下面这条:“Redux 有太多的样板代码,你应该使用 Mobx,可以减少 xxx 行代码”。这条评论也许是对的,但没人考虑得失,Redux 比 Mobx 更多的样板代码,是因为特定的设计约束。它允许你推断应用状态即使应用规模很大。所以围绕 state 的仪式都是有原因的。

Redux 库非常小,大部分时间你都是在处理纯 JavaScript 对象和数组。它比 Mobx 更接近 vanilla JavaScript 。Mobx 通过包装对象和数组为可观察对象,从而隐藏了大部分的样板代码。它是建立在隐藏抽象之上的。感觉像是出现了魔法,但却很难理解其内在的机制。Redux 则可以简单通过纯 JavaScript 来推断。它使你的应用更简单的测试和调试。
另外,我们重新回到单页应用的最开始来考虑,一系列的单页应用框架和库面临着相同的状态管理问题,它最终被 flux 模式解决了。Redux 是这个模式的成功者。

Mobx 则又处在相反的方向。我们直接修改 state 而没有拥抱函数式编程的好处。对一些开发者来说,这让他们觉得像双向绑定。一段时间之后,由于没有引入类似 Redux 的状态管理库,他们可能又会陷入同样的问题。状态管理分散在各个组件,导致最后一团糟。

使用 Redux,你有一个既定的模式组织代码,而 Mobx 则无主张。但拥抱 Mobx 最佳实践会是明智的。 开发者需要知道如何组织状态管理从而更好的推断它。不然他们就会想要直接在组件中修改它。

两个库都非常棒。Redux 已经非常完善,Mobx 则逐渐成为一个有效的替代。

相关推荐:

react-redux中connect的装饰器用法

如何理解 redux

在React中使用Redux的实例详解

위 내용은 Redux와 Mobx의 선택 예시에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.