【问题标题】:React - easy solution for global state or antipattern?React - 全局状态或反模式的简单解决方案?
【发布时间】:2021-10-25 11:46:57
【问题描述】:

在我的 React 应用程序中,我的主要组件包含应用程序的整个状态以及用于修改状态的函数。

为了访问所有子组件中的状态和函数,我通过子组件属性 (app) 从主组件传递 this

class App extends React.Component {

  state = DefaultState;
  funcs = getController(this);

  render() {
    return (
      <Header app={this} />
      <Page app={this} />
      <Footer app={this} />
    )
  }
}


function getController(app: App) {
  return {
    switchPage: (page: string) => {
      app.setState({ page: page });
    },
  }
}

因此,在子组件中,我可以访问状态变量并像这样修改它们:

const HeaderComponent: React.FC<CompProps> = (props) => {
  return (
    <div>
      <h1>{props.app.state.currentPage}</h1>
      <button onClick={(e) => {props.app.funcs.switchPage('home')}}>Home</button>
    </div>
  )
}

这是我为全局状态找到的最快/最简单的解决方案。但是,我从未在任何教程中看到过这一点。我猜主要问题是当全局状态中的单个值发生更改时,整个应用程序将重新呈现,但 React Context API 也是如此。

问题是这种方法有什么缺点或不使用它的理由吗?

【问题讨论】:

  • 我不认为你会希望整个应用程序在一个状态发生变化时更新。 React 的设计目的是避免这种情况,并且只允许在需要时更新组件,从而提供快速且用户直观的 UI。如果您每次更新应用程序,它将重新呈现每个组件。您可以使用 useMemo 来检查每个子组件的状态更改,但是当存在大量状态管理选项时,这似乎需要做很多工作。此外,这种方法需要使用支柱钻孔,这在大型项目中会变得非常混乱。
  • 我使用它的目的是为了简化和易于开发相对简单的应用程序。到目前为止,我从未遇到过任何性能问题。
  • 它会起作用,但它不是“React”的做事方式,并且 React 被积极设计为避免这种状态管理风格。如果您的简单应用开始变得更大更复杂,问题就会出现。
  • 这就像在 Java 或 C# 中传递包含 Main 的类。它有效,但引入了不必要的耦合。您至少应该使用上下文。所以,是的,这个看起来像一个反模式。
  • 除非你的应用程序真的很小很简单,否则它不会长期工作。真正做到这一点的方法是使用像 react-redux 或 mobx 这样的商店

标签: reactjs state this global


【解决方案1】:

您可以将func 保存到导出的let 变量并使用最新版本的func 而无需重新渲染,但由于这种情况并不常见,因此您不会找到太多关于它的信息。由于它只是 javascript,因此任何已知的 hack 都可以使用。此外,您关于 react-context 重新渲染的部分问题是正确的,尽管您必须考虑到它会重新渲染,并且会更加修剪以优化未修改的兄弟姐妹。

您也可以为这些组件提供一个简单的 ref (useRef),这将允许它们访问最新版本的 func,但因为重新呈现页面时 ref 引用本身不会改变,它们不会因功能更改而更新。

我正在使用 react 功能组件,但类库可能非常相似

export let funcs = null

const App = () => {
  funcs = getController();
  render() {
    return (
      <Header />
      <Page />
      <Footer />
    )
  }
}

// header component
import { funcs as appFuncs } from '~/app.js'
const HeaderComponent: React.FC<CompProps> = (props) => {
  return (
    <div>
      {/* same thing can be happened for the state */}
      <button onClick={(e) => {appFuncs.switchPage('home')}}>Home</button>
    </div>
  )
}

挂钩版

const App = () => {
  const ref = useRef();
  funcs = getController();
  ref.current = {state, funcs};

  // note ref.current changes not the ref itself
  render() {
    return (
      <Header app={ref} />
      <Page app={ref} />
      <Footer app={ref} />
    )
  }
}

// header
const HeaderComponent: React.FC<CompProps> = (props) => {
  return (
    <div>
      <h1>{props.app.current.state.currentPage}</h1>
      <button onClick={(e) => {props.app.current.func.switchPage('home')}}>Home</button>
    </div>
  )
}

任何建议或其他技术将不胜感激。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-17
    • 1970-01-01
    • 2021-10-16
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多