反应状态是按钮点击后的一种状态

时间:2019-03-27 00:13:06

标签: reactjs

我正在编写一个简单的react页面,该页面基于单击屏幕上的哪个按钮来呈现2个不同的html表。我遇到的问题是,为每个按钮单击呈现的表都与上一个按钮单击相关联。 (例如,如果我一次单击按钮1,然后单击按钮2,则将显示与按钮1相关联的表格。)

我是新来的人,所以为了更新表,我重构了代码以在App.js类中保存尽可能多的状态,我创建了toggleState回调以将按钮单击与状态更改相关联父对象,然后将其通过端点属性传递给DataProvider。我意识到这可能是状态/ UI断开的地方,但是我不确定原因,因为我坚持尽我所能对原则做出反应。

我的班级结构如下:

        App
    /        \
   /          \
  /            \
DataProvider   ButtonToggle
|
Table

如果相关的话,表类是基于API调用构建表的,那么我将为此添加代码,但是这不会给我造成问题,因此我认为它不是问题的根源。

App.js

import React, { Component } from "react";
import PropTypes from "prop-types";
import DataProvider from "./DataProvider";
import Table from "./Table";
import ButtonToggle from "./ButtonToggle";

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      input : 'employees',
      endpoint : "api/employees/"
    };
    console.log("constructor app: " + this.state.input + "\n" + this.state.endpoint);
  }


  toggleState(input) {
    if(input == "employees") {
      this.setState({input : input, endpoint: "api/employees/"});
    }
    else {
      this.setState({input : input, endpoint: "api/categories/"});
    }
    console.log("toggleState " + this.state.input + "\n" + this.state.endpoint);
  }

  render() {

    return (
      <div className="col-lg-12 grid-margin">
        <div className="card">
          <div className="card-title">
            <div className="row align-items-center justify-content-center">
              <div className="col-3"></div>
              <div className="col-6">
                <h1> Striped Table</h1>
              </div>
              <div className="col-3"></div>
            </div>
              <ButtonToggle toggleInput={ (input) => this.toggleState(input)}/>
            </div>
            <div className="card">
              <div className="card-title"></div>
              <div className="card-body">
              <DataProvider endpoint={this.state.endpoint}
                        render={data => <Table data={data} />} />
               </div>
            </div>
        </div>
      </div>
    );
  }
}


export default App;

DataProvider.js

class DataProvider extends Component {

  static propTypes = {
    endpoint: PropTypes.string.isRequired,
    render: PropTypes.func.isRequired
  };
  constructor(props) {
    super(props);

    this.state = {
        data: [],
        loaded: false,
        placeholder: "Loading..."
    };
  }

  componentWillReceiveProps(props) {
    console.log("dataprov: " + this.props.endpoint);
    this.componentDidMount();
  }

  componentDidMount() {
     fetch(this.props.endpoint)
      .then(response => {
        if (response.status !== 200) {
        return this.setState({ placeholder: "Something went wrong" });
        }
      return response.json();
      })
       .then(data => this.setState({ data: data, loaded: true }));
  }

  render() {
    const { data, loaded, placeholder } = this.state;
    return loaded ? this.props.render(data) : <p>{placeholder}</p>;
  }
}
export default DataProvider;

ButtonToggle.js

class ButtonToggle extends Component {
  constructor (props) {
    super(props);
  }

  render() {
    return (
      <div className="row align-items-center justify-content-center">
      <div className="col-3 center-in-div">
        <button type="button" className="btn btn-info btn-fw" onClick={this.props.toggleInput.bind(this, 'categories')}> Categories </button>
      </div>

        <div className="col-3 center-in-div">
          <button type="button" className="btn btn-info btn-fw" onClick={this.props.toggleInput.bind(this, 'employees')}>
           Employees
         </button>
         </div>

          <div className="col-6"></div>
      </div>
    );
  }

}
export default ButtonToggle;

Table.js:我不认为这是个问题,但我可以纠正。

import React from "react";
import PropTypes from "prop-types";
import key from "weak-key";

const Table = ({ data }) =>
    !data.length ? (
    <p>Nothing to show. Records: {data.length} </p>
            ) : (
    <div className="table-responsive">
      <h2 className="subtitle">
    Showing <strong>{data.length} items</strong>
      </h2>
      <table className="table table-hover">
        <thead>
          <tr>
    {Object.entries(data[0]).map(el => <th key={key(el)}>{el[0]}</th>)}
          </tr>
        </thead>
        <tbody>
    {data.map(el => (
             <tr key={el.id}>
                 {Object.entries(el).map(el => <td key={key(el)}>{el[1]}</td>)}
            </tr>
             ))}
        </tbody>
      </table>
    </div>
             );
Table.propTypes = {
    data: PropTypes.array.isRequired
};
export default Table;

1 个答案:

答案 0 :(得分:0)

以下是我能想到的最低工作代码。您的Button和Table组件可以是哑组件,它们将从父组件中获取数据并显示出来。 您的Parent或container组件将具有逻辑来设置Button和Table组件的属性。 由于表和按钮组件很笨,因此您可以使用功能组件。

我添加了用于调用api的代码(我试图模仿api调用)并在同一父组件中获取数据,您可以将其分离出来。 您可以根据需要进行样式和验证。 让我知道您是否需要其他帮助。

class ParentComponent extends Component {
  constructor() {
    super();
    this.state = {
      name: "Category"
    }
    this.onBtnClick = this.onBtnClick.bind(this);
  }

  componentDidMount() {
    this.getData(this.state.name)
  }
  getData(name) {
    if (name === "Category") {
      this.apiCall("/Category").then((data) => {
        this.setState({ data: data })
      })
    } else {
      this.apiCall("/Employee").then((data) => {
        this.setState({ data: data })
      })
    }
  }

  apiCall(url) {
    return new Promise((res, rej) => {
      setTimeout(() => {
        if (url === "/Employee") {
          res([{ "Emp Name": "AAA", "Emp Age": "20" }, { "Emp Name": "BBB", "Emp Age": "40" }])
        } else {
          res([{ "Cat Id": "XXX", "Cat Name": "YYY" }, { "Cat Id": "MMM", "Cat Name": "NNN" }])
        }
      }, 1000)
    });

  }

  onBtnClick(name) {
    let newName = "Category"
    if (name === newName) {
      newName = "Employee"
    }

    this.setState({ name: newName, data: [] }, () => {
      this.getData(newName);
    })
  }
  render() {
    return (<>
      <ButtonComponent name={this.state.name} onBtnClick={this.onBtnClick}></ButtonComponent>
      <TableComponent data={this.state.data} />
    </>)
  }
}
const ButtonComponent = ({ name, onBtnClick }) => {
  return <Button onClick={() => { onBtnClick(name) }}>{name}</Button>
}


const TableComponent = ({ data }) => {
  function getTable(data) {
    return < table >
      <thead>
        <tr>
          {getHeading(data)}
        </tr>
      </thead>
      <tbody>
        {getRows(data)}
      </tbody>
    </table >
  }
  function getHeading(data) {
    return Object.entries(data[0]).map((key) => {
      return <th key={key}>{key[0]}</th>
    });
  }
  function getRows(data) {
    return data.map((row, index) => {
      return <tr key={"tr" + index}>
        {Object.entries(data[0]).map((key, index) => {
          console.log(row[key[0]]);
          return <td key={"td" + index}>{row[key[0]]}</td>
        })}
      </tr>
    })
  }
  return (
    data && data.length > 0 ?
      getTable(data)
      : <div>Loading....</div>
  )
}