如何根据另一个组件的事件处理程序更新一个组件?

Posted

技术标签:

【中文标题】如何根据另一个组件的事件处理程序更新一个组件?【英文标题】:How to update one component based on event handler of another component? 【发布时间】:2019-04-01 00:49:15 【问题描述】:

我的 index.js 文件中有两个组件(标题和边栏),如下所示

import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import 
    BrowserRouter as Router,
    Route
 from "react-router-dom";
import './index.scss';
import './responsive.scss';
import Sidebar from './sidebar';
import Header from './header';
import Home from './home';
import Products from './products';
import Variant from './variant';
import Variety from './variety';
import * as serviceWorker from './serviceWorker';




ReactDOM.render(
    <Router>
        <div className="wrapper">
            <Header />
            <Sidebar />
            <div id="content">
                <Route exact path="/" component=Home />
                <Route path="/products" component=Products />
                <Route path="/variant" component=Variant />
                <Route path="/variety" component=Variety />
            </div>
        </div>
    </Router>
    , document.getElementById('root'));

serviceWorker.unregister();

我的 Header 组件中有一个按钮,我想向它添加一个 onClick 事件处理程序,因此当单击 Sidebar 组件中的侧边栏时,将会切换。 现在我的问题是我无法连接这两个组件。我什至尝试使用此链接How To Pass Events Between Components 中的建议,但问题是该事件的目标是更改子组件中定义的所有元素。 我已经阅读了有关 createPortal() 的一些内容,但建议访问组件外部的 DOM,并且由于我试图从另一个组件访问组件,因此我不确定是否应该这样做。 提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

为了连接组件,您应该使用存储在所有组件之间共享应用程序状态。 Redux 或类似的东西可以做到。

主要思想是您更改 Header 组件中的状态,Sidebar 将监听此状态并在需要时自行更新。

【讨论】:

【参考方案2】:

有几种方法。

    您可以使用 Redux。 使用 React 上下文 API https://reactjs.org/docs/context.html

您可以执行以下操作

// IN MAIN FILE
state =
    sidebarOpen : false

<header toggleSidebar =  this.toggleSidebar  />
<sidebar  sidebarOpen =  this.state.sidebarOpen /> 

toggleSidebar()
    //UPDATE STATE
    this.setState(
        sidebarOpen : !(this.state.sidebarOpen)
    )


// IN HEADER

onButtonClick()
    this.props.toggleSidebar()


IN SIDEBAR

componentWillReceiveProps(props)
    //LOGIC FOR UPDATING SIDEBAR YOU WILL RECIEVE UPDATED STATE HERE

【讨论】:

【参考方案3】:

首先,简单说一下这两个组件的连接。React中的数据传输建议是从父组件传递到子组件。这是Lifting State Up。所以通常使用回调来改变header的父组件并传递数据返回侧边栏。现在 redux 与 react 配合得很好。所以,只需为侧边栏设置一个状态,并在 Header 的 onClick 中绑定一个函数。然后在 onClick 中添加一些东西。像这样:

<header onClick =  this.expand.bind(this)  />
<sidebar  sidebar =  this.state.sidebar />

顺便说一句,react 为我们提供了一些传递数据的方法。例如,在组件嵌套复杂且很难找到公共父组件时使用上下文。

第二,“事件针对子组件中定义的所有元素的变化”。这个问题是因为react是如何工作的。你可以使用shouldComponentUpdate来避免它。但这里不推荐。

第三,关于React Portal,添加到React v16中,用于在父组件之外渲染子组件。这个答案很好,如果你想了解的话。How to use ReactDOM.createPortal() in React 16?。侧边栏和标题组件处于同一级别。所以我认为这不是必需的。

【讨论】:

【参考方案4】:

正如大家所回答的,这些是一些很好的解决方案。但是你也提到了你的限制。您也可以尝试以下一种。

let showSidebar = true;

// Function to handle toggle
const handleClick = () => 
  showSidebar = !showSidebar
  renderApp()


// Make renderApp function
const renderApp = () => 
 ReactDOM.render(
    <Router>
        <div className="wrapper">
            <Header handleClick=handleClick/> // call this function onClick inside your Header component 
             showSidebar && <Sidebar />       // toggle the Sidebar
            <div id="content">
                <Route exact path="/" component=Home />
                <Route path="/products" component=Products />
                <Route path="/variant" component=Variant />
                <Route path="/variety" component=Variety />
            </div>
        </div>
    </Router>
    , document.getElementById('root'));
;
renderApp(); // Call renderApp for the first time

serviceWorker.unregister();

【讨论】:

以上是关于如何根据另一个组件的事件处理程序更新一个组件?的主要内容,如果未能解决你的问题,请参考以下文章

如何将按钮事件连接到另一个 React 组件?

Event System 事件系统

如何从另一个组件重新获取 graphql 查询?

如何在 React 子组件中设置事件处理程序

如何在纯函数式 React 组件中处理事件

如何在服务器端 React 中访问 JSX 组件的 DOM 事件处理程序