【问题标题】:Handling button state and actions in redux在 redux 中处理按钮状态和操作
【发布时间】:2019-09-13 19:42:58
【问题描述】:

我是 react 和 redux 的新手。

应用程序概述:我有一个带有两个按钮的 ToggleButtonGroup。单击按钮时,我想为相应的按钮输出一个表格。我们根据按钮点击过滤的表格。

问题:我不确定如何在我的项目中为按钮功能设置动作、状态和减速器。我的按钮是一个组件。对按钮使用动作和减速器是最佳实践吗?我如何将这些操作传递给其他组件?感谢任何示例或资源。

这是我的 Button.tsx 文件

import React, { Component, useState  } from 'react'
import ToggleButtonGroup from 'react-bootstrap/ToggleButtonGroup';
import ToggleButton  from 'react-bootstrap/ToggleButton';



function ToggleButtonGroupControlled() {
    const [value, setValue] = useState([1, 2]);

    return (
      <ToggleButtonGroup type="checkbox" value={value} onChange={() => setValue(value)}>
        <ToggleButton value={1}>PA Probes</ToggleButton>
        <ToggleButton value={2}>Convential Probes</ToggleButton>
      </ToggleButtonGroup>
    );
  }


export class Buttons extends Component {
    render() {
        return (
            <div>
                <ToggleButtonGroupControlled />  
            </div>
        )
    }
}

export default Buttons

这是我的 types.ts 文件

export const TOGGLE_PA_PROBES = 'TOGGLE_PA_PROBES';
export const TOGGLE_CONVENTIONAL_PROBES = 'TOGGLE_CONVENTIONAL_PROBES';

这是 buttonAction.ts 文件

import{ TOGGLE_PA_PROBES, TOGGLE_CONVENTIONAL_PROBES } from './types';

export function togglePAProebs(){

}

export function toggleConventionalProbes(){
}

这是我的 buttonReducers.ts 文件

import{ TOGGLE_PA_PROBES, TOGGLE_CONVENTIONAL_PROBES } from '../Actions/types';


export function ButtonReducer(state, action){
    switch(action.type){
        default:
            return state;
    }
}

【问题讨论】:

    标签: reactjs typescript redux


    【解决方案1】:

    我假设你了解 redux 和 react-redux 的基础知识。简而言之,你知道一个动作被分派到一个商店。

    在现实世界中,就好像您更改电视上的频道一样,(1) 您向遥控器发送 CHANGE_CHANNEL 操作,(2) 遥控器将接收发送的操作并发送该操作将频道信息发送到您的电视(减速器),然后 (3) 您的电视(减速器)将与您的有线电视提供商(商店)通信,并在您可用时返回频道数据。

    该流程很重要,因为它也可以在您的示例中使用。首先,假设您有一家带有一些探针的商店。在切换您的复选框时,您将发送一个操作 FILTER,例如,它将从数据库列表中过滤掉需要显示的探针,然后使用过滤后的探针调用您的 reducer 以更新您的商店并将该数据发送回您的调度员。

    当你第一次加载你的页面时,我也想你想显示所有探测的列表,所以你还需要一个 FETCH 操作来在 componentDidMount 上分派。考虑到这一点,我们可以想出一个这样的类型文件:

    types.js

    export const TOGGLE_PROBES = "TOGGLE_PROBES"; 
    export const LOAD_PROBES = "LOAD_PROBES";
    

    现在类型已经定义好了,我们可以创建我们的动作了,

    import { TOGGLE_PROBES, LOAD_PROBES } from "./types";
    
    const dbProbes = [
      { title: "pa probe 1", type: 1 },
    
      { title: "pa probe 2", type: 1 },
    
      { title: "conditional probe 1", type: 2 },
    
      { title: "conditional probe 1", type: 2 }
    ];
    
    function toggleProbes(filtered) {
      return {
        type: TOGGLE_PROBES,
        filtered: filtered
      };
    }
    
    function loadProbes(probes) {
      return {
        type: LOAD_PROBES,
        probes: probes
      };
    }
    
    export function fetchProbes() {
      return function(dispatch) {
        dispatch(loadProbes(dbProbes));
      };
    }
    
    export function filterProbes(filter) {
      return function(dispatch) {
        const filtered = dbProbes.filter(probe => filter.includes(probe.type));
        dispatch(toggleProbes(filtered));
      };
    }

    请注意,我创建了一个名为 dbProbes 的虚假探测器列表。在现实世界中,您可能会访问数据库来过滤您的探测。

    设置完所有动作后,您终于可以在 reducer 上工作并相应地更新您的状态,

    import { TOGGLE_PROBES, LOAD_PROBES } from "./types";
    
    const initialState = {
      probes: []
    };
    
    function ButtonReducer(state = initialState, action) {
      switch (action.type) {
        case TOGGLE_PROBES:
          return { ...state, probes: action.filtered };
        case LOAD_PROBES:
          return { ...state, probes: action.probes };
        default:
          return state;
      }
    }
    
    export default ButtonReducer;

    为了能够在您的组件中调度它,您确实需要设置 redux。在你的 index.js 中,你可以同时使用 react、react-redux 和 react-thunk 来实现。 React-thunk 是一个中间件,通常与 redux 一起用于异步调用。

    import React from "react";
    import ReactDOM from "react-dom";
    import { Provider } from "react-redux";
    import { createStore, applyMiddleware } from "redux";
    import thunk from "redux-thunk";
    import "./styles.css";
    import Buttons from "./Buttons";
    import rootReducer from "./store/reducer";
    
    const store = createStore(rootReducer, applyMiddleware(thunk));
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(
      <Provider store={store}>
        <Buttons />
      </Provider>,
      rootElement
    );

    首先,在您的 Button 组件中,您可能只想先显示初始列表,因此您需要使用名为 connect 的 react-redux 高阶组件,顾名思义,它将连接您的商店并将商店的状态映射到调度程序和道具。

    import React, { Component } from "react";
    import ToggleButtonGroupControlled from "./ToggleButtonGroupControlled";
    import { connect } from "react-redux";
    import { fetchProbes } from "./store/action";
    
    export class Buttons extends Component {
      componentDidMount() {
        this.props.fetchProbes();
      }
    
      render() {
        let probes = null;
    
        if (this.props.probes) {
          probes = this.props.probes.map(probe => <li>{probe.title}</li>);
        }
    
        return (
          <div>
            <ToggleButtonGroupControlled />
            <ul>{probes}</ul>
          </div>
        );
      }
    }
    
    function mapStateToProps(state) {
      return {
        probes: state.probes
      };
    }
    
    function mapDispatchToProps(dispatch) {
      return {
        fetchProbes: () => dispatch(fetchProbes())
      };
    }
    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(Buttons);

    最后,您的切换按钮组件可以正确地向您的 actions.js 发送一个 TOGGLE_FILTER 操作,这将过滤探针,然后将操作发送到 reducer,reducer 将更新您的状态并返回更新后的状态,此时是映射到 Button.js 组件中的组件道具。

    import React, { useState } from "react";
    import { ToggleButtonGroup } from "react-bootstrap";
    import { ToggleButton } from "react-bootstrap";
    import { connect } from "react-redux";
    import { filterProbes } from "./store/action";
    
    function ToggleButtonGroupControlled(props) {
      const [value, setValue] = useState([1, 2]);
    
      const toggleChangeHandler = newValue => {
        setValue(newValue);
        props.filterProbes(newValue);
      };
    
      return (
        <ToggleButtonGroup
          type="checkbox"
          value={value}
          onChange={e => toggleChangeHandler(e)}
        >
          <ToggleButton value={1}>PA Probes</ToggleButton>
          <ToggleButton value={2}>Convential Probes</ToggleButton>
        </ToggleButtonGroup>
      );
    }
    
    function mapDispatchToProps(dispatch) {
      return {
        filterProbes: types => dispatch(filterProbes(types))
      };
    }
    
    export default connect(
      null,
      mapDispatchToProps
    )(ToggleButtonGroupControlled);

    redux 很酷的地方在于它允许全局状态,因此您可以从 ToggleButtonGroupControlled 组件调度和更改您的探针列表,但是该存储(探针列表)也可用于您决定连接的其他组件到您的商店,在本例中为 Button.js。

    您可以在此处检查正在运行的最终代码并为您的问题做好准备:

    要了解有关 redux-thunk 的更多信息,请访问此处:https://github.com/reduxjs/redux-thunk

    另外,这里有一本免费的 redux 书籍,您可以快速浏览一下:https://leanpub.com/redux-book

    【讨论】:

    • 谢谢。你的解释很有道理。我会继续练习,希望我能做到同样出色。
    【解决方案2】:

    Redux 对于这个例子来说可能是多余的,但这完全取决于你的表在组件层次结构中的哪个级别与你的 ToggleButtonGroupControlled 组件相关。 查看表格组件对您的问题会有所帮助,它是否位于单独的文件/路由中?

    我会从简单的开始,通过创建一个 onChange 属性将值从您的 ToggleButtonGroupControlled 组件中传递出去。现在你的ToggleButtonGroupControlled 组件并没有增加更多的功能 比第三方ToggleButtonGroup 组件,所以它有点难以推理。

    另外,如果你确实选择了 redux 路线,因为你需要全局状态下的数据,那么你可能会放弃你在这里拥有的本地状态,并从你的 redux 存储中选择它并传递到组件中

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-02
      相关资源
      最近更新 更多