1

我正在尝试围绕 Redux 重构我的 React 应用程序,并且感到困惑。

一个网站说:

组件从其父组件接收道具。不应在组件内部修改这些道具。

另一个说:

您曾经能够使用 setProps 和 replaceProps 更改道具,但这些已被弃用。在组件的生命周期中,道具不应更改(认为它们是不可变的)。

所以我应该考虑 props 在组件的生命周期内是不可变的。好的,那么,另一种选择是状态(React状态,我理解它与Redux状态完全不同。好的......)

React 状态是组件的可变状态。它属于组件,并且与 props 不同,它可以在组件的生命周期中更改。好的。在 Redux 的上下文之外,我完全明白这一点。每个组件都拥有自己的可变状态,并将它需要的东西作为 props 传递给它的子组件,这些 props 用于不可变的子组件。当状态改变时,它会导致组件重新渲染它的子组件,并根据需要为它们提供新的道具。

现在介绍 Redux。Redux 商店为整个应用程序保存一个状态现在这会取代任何 React 状态吗?Redux 状态的所有元素是否都作为 props 传递给 React 组件?有mapStateToProps这似乎暗示了这一点。那么我现在可以完全忘记 React 状态吗?

我认为组件的生命周期是持久的,比如说,只要用户可以在屏幕上看到东西。但是如果 props 在组件生命周期中不能改变,而现在一切(从 React 的角度来看)都是 props——这是否意味着生命周期只需要 Redux 刷新它的存储?

4

3 回答 3

2

正如 Dan Abramov 在他著名的You may not need redux文章中指出的那样,只有在需要跨应用程序持久性时才应该使用 Redux 。当数据是短暂的(想想在简单视图中打开的选定手风琴),您可以安全地将您的状态存储在本地状态中。所以:

这现在(Redux)是否取代了任何 React 状态? 如果你愿意,可以。但这不是强制性的。

Redux 状态的所有元素是否都作为 props 传递给 React 组件? 通常,是的。

那么我现在可以完全忘记 React 状态吗? 是的你可以。虽然不是强制性的,但本地/redux 状态可以幸福地生活在一起。

[...] 这是否意味着生命周期只需要 Redux 刷新它的存储? 渲染发生在任何状态(本地或 redux)更改时。

于 2018-12-17T16:52:38.653 回答
2

Lucy Bain 的帖子作为一个很好的解释者,但请注意,提到的提到的setProps是一个非常旧的 React 版本,而 React 0.14 的链接发行说明将这些说明描述为仅对更新应用程序中的顶级组件有用。今天,如果你真的需要更新根组件的 props,你会调用ReactDOM.render(<MyApp newProp={123} />)第二次。

有关在 Redux 和 React 组件之间拆分状态的一些经验法则,请参阅Redux 常见问题解答条目,以帮助确定每个状态的位置。

我还鼓励您通读React-Redux 文档以了解它们如何组合在一起。

于 2018-12-17T16:45:46.820 回答
1

我认为您首先需要了解的是 Redux 循环,它是这样的:

Action Creator->Action->dispatch->Reducers->State

Action Creator 是一个函数,它将返回一个称为 Action 的纯 JavaScript 对象。该操作将有一个typepayload,它提供了它正在做什么的上下文,例如,创建一个保险单,它看起来像这样:

// People dropping off a form (Action Creator)
const createPolicy = (name, amount) => {
  return { // Action(a form in this analogy)
    type: 'CREATE_POLICY',
    payload: {
      name: name,
      amount: amount
    }
  };
};

所有动作创建者看起来都与您在此处看到的相同,但有一些小的变化。

但我知道问题在于理解循环及其目的,而不是语法。

所以你想了解你的动作创建者需要在你的 React 应用程序中扮演什么角色,然后到你的 Reducer 并弄清楚他们的角色,但真正在你弄清楚了最难的部分之后,动作创建者,其余的开始下降到位。

接收动作并将其dispatch分派给所有不同的Reducers. dispatch 是 Redux 库本身的一部分,所以你不需要把它写出来,你的问题是mapStateToProps如果你使用 helper 将它与更高阶的组件联系起来connect(),整个过程就像手动覆盖调度过程。

Reducers 背后的想法是我们写出函数,每个函数都在应用程序内部建模不同的行为。每个reducer 都被一个Action 调用,reducer 检查该action 并根据该action 确定是否修改行为。

因此,行动创建者就像是提出保险索赔的人,而行动就是实际索赔。这些索赔转到这些不同的部门,称为减速器。

因此,按照保险索赔的类比,我可能想要创建的减速器将是一个索赔历史减速器,如下所示:

// Reducers (Departments)
const claimsHistory = (oldListOfClaims, action) => {

};

因此,reducers 的工作是确定它是否关心它正在接收的操作类型。如果是,type createClaim那么我们要确保函数内的代码提取有效负载属性并将其添加到声明列表中,如果不是,则返回声明列表不变,看起来像这样:

// Reducers (Departments)
const claimsHistory = (oldListOfClaims, action) => {
  if(action.type === 'CREATE_CLAIM') {
    // we care about the action (claim)
    return [...oldListOfClaims, action.payload]
  }
  // we dont care about the action (form)
};

所以我只是使用 ES2015 语法,它接受一个数组,获取所有记录并将它们添加到一个全新的数组中,然后添加action.payload.

它相当于做const numbers = [1,2,3]然后[...numbers, 4]输出: (4) [1, 2, 3, 4]

或者相当于,oldListOfClaims.push(action.payload);但这个和我使用的有明显的区别。

在我用于 reducer 的语法中,我正在创建一个全新的数组并向其中添加记录,而该push()方法正在修改现有数组。

我们总是希望避免修改 reducer 中现有的数据结构。你永远不会看到push()减速器的内部。

然后是我们不关心动作的情况:

// Reducers (Departments)
const claimsHistory = (oldListOfClaims, action) => {
  if(action.type === 'CREATE_CLAIM') {
    // we care about the action (claim)
    return [...oldListOfClaims, action.payload]
  }
  // we dont care about the action (form)
  return oldListOfClaims;
};

接下来,您需要处理第一次调用 reducer 时没有数据传递给它的情况。我们基本上会收到 的值undefined。我们需要默认第一个参数的值。

// Reducers (Departments)
const claimsHistory = (oldListOfClaims = [], action) => {
  if(action.type === 'CREATE_CLAIM') {
    // we care about the action (claim)
    return [...oldListOfClaims, action.payload]
  }
  // we dont care about the action (form)
  return oldListOfClaims;
};

所以undefined被一个空数组替换。

因此,在实现 Redux 以及随之而来的细粒度规则(例如确保不修改传入的数组并确保始终返回一些值)时,弄清楚你的操作和 reducer 是困难的部分。

reducer 的总体目标是将一些现有数据作为操作传递给它,并根据操作的内容查找并返回现有数据。

所以这是让你开始的所有基线内容。在所有这些中,您想要返回一个 Redux 存储的新实例。

根据您的项目,您可能有 1 到 3 个或更多动作创建者和缩减者。然后,您将所有这些连接到一个名为 store 的对象中,该对象只是不同 action 和 reducer 的组合。

因此,在您的组件中的某个地方,您将添加如下内容:const { createStore, combineReducer } = Redux;

这是你的combineReducers样子:

const ourDepartments = combineReducers({
  accounting: accounting,
  claimsHistory: claimsHistory,
  policies: policies
});

然后您完成创建商店,如下所示:

const store = createStore(ourDepartments);

store;

store代表整个 Redux 应用程序。它包含对所有不同减速器的引用以及对这些减速器或数据产生的所有状态的引用。

store对象具有一些有用的功能,例如dispatch函数。为了调用dispatch(),我们必须传入由动作创建者创建的动作,然后将其传递给store.dispatch().

const store = createStore(ourDepartments);

const action = createPolicy('Alejandra', 35);
console.log(action);

store.dispatch();

当您控制台注销时,action您应该看到您具有操作类型和有效负载:

{type: "CREATE_POLICY", payload: {…}}

然后您采取该行动并将其传递给store.dispatch()这样的:

到目前为止,您可能看到了一个错误,指出 Action 必须是一个普通的 JavaScript 对象等等,一旦您像这样传递 action,这个错误就会消失:

store.dispatch(action);

您可以检查以查看应用程序的打印状态,如下所示:

console.log(store.getState());

{accounting: 135, claimHistory: Array(0), policies: Array(1)} accounting: 135 claimHistory: [] policies: ["Alejandra"] proto : Object

现在您可以开始传递如下操作:

store.dispatch(createPolicy('Alejandra', 35));
store.dispatch(createPolicy('Ben', 20));
store.dispatch(createPolicy('Daniel', 78));

store.dispatch(createClaim('Alejandra', 120));
store.dispatch(createClaim('Ben', 50));

store.dispatch(deletePolicy('Daniel'));

console.log(store.getState());

控制台输出:

{accounting: 63, claimHistory: Array(2), policies: Array(2)} accounting: 63 claimHistory: Array(2) 0: {name: "Alejandra", amountOfMoneyToCollect: 120} 1: {name: "Ben", amountOfMoneyToCollect:50} 长度:2 proto:Array(0) 策略:Array(2) 0:“Alejandra”1:“Ben”长度:2 proto:Array(0) proto:对象

这就是 Redux 库的工作方式

好的,所以我向您展示了它是如何独立工作的,但是 Redux 和 React 这两个库如何相互交互?

所以是的,随着 Redux 的实现,我们使用组件级状态的频率要低得多。我们通常将所有数据存储在 Redux 中。

在某些情况下,我们希望在 Redux 和 React 组件中都有状态,但一般来说,你在 React 应用程序中的所有状态现在都在 Redux 中,这样可以转化为更简单的 React 应用程序。

假设你有一些 iTunes 类型的应用程序,我们如何将它与 Reactjs 组合在一起?

所以这将是你没有 redux 的应用程序:

在此处输入图像描述

所以在这里你SongDetail只需要知道你当前选择的歌曲是什么。因此,您的App组件将其SongDetail作为道具传递给它,然后SongDetail将其渲染到屏幕上。

单独使用 React,这将是一个简单直接的应用程序。

那么您的应用程序如何使用 Redux 进行更改?

在此处输入图像描述

所以就像之前一样,我们将有一个App组件 a SongListand SongDetail,但是该App组件将传递很少的信息到SongListand SongDetail

相反,我们将把这些创建歌曲列表和选择歌曲以及当前选择的歌曲是什么的想法抽象到 redux 应用程序中。

因此,您将拥有一个生成歌曲列表的reducer 和一个记录当前选定歌曲的reducer。这些是您的应用程序中的两个状态。

最后,我们将确保我们有一个动作创建者来以某种方式改变你的状态。这是您在 redux 应用程序中更改状态的唯一方法。

所以你的动作创建者可能被称为选择歌曲,它将调度一个动作并告诉选定的歌曲reducer更新它的数据并反映新的当前选择的歌曲。

这就是你使用 Redux 的应用程序。

于 2018-12-19T18:22:13.817 回答