在反应组件内部保持强 ui 相关状态是一种不好的做法吗?

Is it a bad practice to keep strong ui related state inside of the react component?

我正在将我的 reactJs 应用程序迁移到 redux/mobx。 现在我有 3 个组件,每个组件都具有以下结构:

name:string,
surname:string,
showError: boolean,
loading:boolean

如您所见,将 name/surname 移动到集中式存储库以维护全局状态是有意义的。 我不太确定 showError 和加载:它们是布尔值,用于显示错误消息和特定组件内部的微调器。

我个人不喜欢将这样的 "UI-related state" 置于集中状态的想法,我想让它留在特定组件内部,因为其他组件永远不需要 access/update这样的东西。

所以我的想法是:

this.state = {showError, loading};
this.businessState = props.state;

简而言之,我将继续使用 React 的 setState() 函数更新 "state",同时让 redux/mobx 管理所谓的 "business state"。

这是一个好的做法还是我做的事情特别糟糕?

我个人对此没有问题,因为 'loading' 和 'showError' 与状态相关,而不是 UI 组件。它基本上是说,当我从 API 调用填充我的状态时,它是否已经完成并且有什么问题吗? UI 组件相应显示。

我会将 showError 设置为字符串或字符串[],具体取决于从您的 BE 系统抛出的错误的结构。

我还会将您的状态分解为特定的减速器,这些减速器处理特定的业务功能并根据特定的业务功能加载状态,而不是按页面上的组件加载。

希望对您有所帮助。

就我个人而言,我建议为大多数 components 创建 store,根据我的经验,大多数 stores 实际上是 ViewStore's。如果你在多个 components 上有类似 loadingerrors 的逻辑,那么做这样的事情会更容易:

class BaseViewStore {
    @observable loading = false
    @observable showError = false
}

然后您的 component store 将扩展此 store,您将在此 base store 中拥有可重用的逻辑。 component 特定的所有内容当然都会包含在那个特定的 store 中。这样你的 components 就会干净,没有 personal state (在 component 本身内)并且可以很容易地用其他组件替换,因为你的行为(状态)将在 stores.

我不确定这是否是最佳做法。但是当您执行一些异步操作(例如从 API 获取数据)时,会使用加载状态。获取此类数据的最佳做法是通过行动来完成。我通常在 action 中做的是在调用 API 之前分派一个加载状态,并在获取数据后分派一个将 loading 设置为 false 的 reducer。

所以,在我看来。我会将加载状态存储在 redux 中,而不是使用组件状态。

会是这样的

action.js

getData = () => {
   return (dispatch) => {
      dispatch({ type: LOADING });
      callApiToGetData()
         .then(data => {
            dispatch({ type: SUCCESS, data })
         })
         .catch(e => {
            dispatch({ type: ERROR, error: e })
         })
   }
}

reducer.js

const initialState = {
  data: null,
  loading: false,
  error: null
}

function reducer(state = initialState, action) {
  switch (action.type) {
    case LOADING:
       return { ...state, loading: true }
    case SUCCESS:
       return { ...state, loading: false, data: action.data, error: null }  
    case FAIL:
       return { ...state, loading: false, error: action.error }
    default:  
       return state
}