【问题标题】:How to change state of component from anywhere without Redux?如何在没有 Redux 的情况下从任何地方更改组件的状态?
【发布时间】:2019-01-31 20:32:40
【问题描述】:

这是不是不好的做法?

  1. 从组件中导出状态变化函数
  2. 从其他文件导入。
  3. 调用函数改变状态?

通过这种方式,我们可以从任何地方更改某些组件状态。

例如...

我们想从任何地方更改Model.js 状态。

Modal.js

import React from 'react';

export let toggleModal;

export default class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
    };
    toggleModal = this.toggleModal;
  }

  toggleModal = () => {
    this.setState({ open: !this.state.open });
  };

  render() {
    const { open } = this.state;
    return <div style={{ color: 'red' }}>{open && 'Hello Modal'}</div>;
  }
}

App.js(一些顶级组件)

import React from 'react';
import Modal from './Modal';

export default () => (
    <>
        ...
        <Modal />
        ...
    </>
);

Somewhere.js

import React from 'react';
import {toggleModal} from './Modal';

export default () => (
    <>
        <h1>Hello!</h1>
        <button onClick={() => toggleModal()}>open Modal!</button>
    </>
);

  

但是 React 官方文档中没有参考,所以这是不好的做法吗?

React Docs 推荐什么...

  1. 只需传递函数道具即可将父状态从父状态更改为子状态
  2. 使用上下文
  3. Redux 或 Mobx

但是,这些对我来说太复杂了。

此处为示例代码
https://next.plnkr.co/edit/37nutSDTWp8GGv2r?preview

【问题讨论】:

  • 如果你认为 redux 太复杂,那么你会陷入混乱,直接改变其他组件的状态,随着时间的推移会变得更加复杂。试试 redux,还不错。
  • 您不能导出setState(),因为它绑定到将在运行时创建的组件实例。导入/导出发生在编译时。但是要回答这个问题:是的,将setState() 暴露给外部代码通常应该被认为是一种不好的做法。它使您的应用在发展过程中难以推理。
  • 您可以在任何地方使用 Redux 更改状态。

标签: reactjs


【解决方案1】:

这里的&lt;Modal /&gt; 是子组件。因此,要在子组件中调用函数,您可以简单地使用 Ref. 您可以参考this page 了解更多关于 Ref.的​​信息。

您可以将一个类变量作为引用分配给这个孩子,并使用这个类变量作为一个对象来调用它的函数。

【讨论】:

    【解决方案2】:

    一开始,一切似乎都非常艰巨和困难。但是当我们开始接触它们时,它给了我们更多的信心去挖掘。 我建议使用 redux,这就是我们解决道具钻孔问题的方式。您可以调度一个动作并将 reducer 连接到相应的组件,该组件在更新状态时将重新呈现。这是我向大多数人推荐的用一个真实的例子来学习 redux 的故事: Understanding Redux: The World’s Easiest Guide to Beginning Redux

    除此之外,您还可以参加 Dan Abramov,该库的作者,egghead.io 上的免费 redux 课程: Getting Started with Redux

    【讨论】:

      【解决方案3】:

      您遇到的问题,几乎就像您的代码示例一样,是这样的:

      它不起作用:您的 toggleModal() 方法需要 this 来引用实际的组件实例。当您的 onClick() 处理程序触发时,您将 toggleModal() 作为普通函数调用。 this 上下文将是错误的,因此充其量(在您的示例中)您将收到错误,因为您尝试调用 undefined最坏情况(一般来说)你最终会调用错误的方法。

      当您考虑它时,对于任何重要的 React 组件,您将很难获得对当前正在使用的实际实例的引用:您必须确保您没有忘记在正确的组件实例,并且您还必须考虑可能出于任何原因“随意”创建/销毁实例。例如:如果您的组件作为其他组件的render() 方法的一部分被间接渲染怎么办?像这样的多层间接使得它变得更加困难。

      现在,您可以通过放弃滥用ref 来解决所有问题,但是您会发现现在您必须跟踪哪个 ref 引用了哪个特定实例,如果您碰巧在一个渲染树中需要考虑多个组件...

      【讨论】:

      • 为了避免this上下文会出错,我加了toggleModal = this.toggleModal;你怎么看?
      【解决方案4】:

      当您认为某个组件需要处理其兄弟组件的状态时,解决方案通常是将状态提升一级。

      export default class Modal extends React.Component {
        render() {
          const { isOpen } = this.props;
          return <div style={{ color: 'red' }}>{isOpen && 'Hello Modal'}</div>;
        }
      }
      
      
      export default class Home {
          this.state = {
            isOpen: false,
          };
          toggleModal = () => {
            this.setState({ isOpen: !this.state.isOpen });
          }
      
          render() {
            const { isOpen } = this.state;
            return (
              <>
              <h1>Hello {name}!</h1>
              <button onClick={() => this.toggleModal()}>open Modal!</button>
              <Modal isOpen={isOpen}/>
              <p>Start editing and see your changes reflected here immediately!</p>
              </>
            )
          }
      }
      

      这样 Home 处理状态并解决您的问题。 如果需要将状态“深入”到子级,这可能会很烦人,这是 redux 或 react-context 无法解决的问题。

      【讨论】:

        【解决方案5】:

        我发现如果在特殊情况下,我的方式是好的

        特殊情况意味着类似于 customAlert 组件。

        在 App 中一次只挂载一个 customAlert 组件实例是可以的。

        为了实现这个...

        1.使用ref访问和更改DOM
        2.将状态改变函数或组件附加到window并调用window.function
        3.我的案例:导出状态改变函数并从其他文件中导入。

        这里是如何处理反应上下文 https://next.plnkr.co/edit/EpLm1Bq3ASiWECoE?preview

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-10-29
          • 2018-03-05
          • 2016-12-24
          • 1970-01-01
          • 2020-09-13
          • 2019-02-20
          • 2018-05-21
          • 1970-01-01
          相关资源
          最近更新 更多