Skip to content
Advertisement

Component does update but if statement isn’t working

I’ve found a weird behavior in my react code. I’m fairly new to react and can’t figure it out.

In the past few days, I’ve created a nice dashboard and want to add a data page with CRUD transactions. I want to change the text inside the search button, when the searchForm state is true, but it does only work after the component updated, not on first rendering. I’ve initiated the searchForm state with false and on searchBtnClick the state gets set to true. But the text inside the button doesn’t change.

import React, { Component, Fragment } from 'react';

import SideBar from '../../components/navBar/SideBar';
import SearchForm from '../../components/forms/SearchForm';
import TransactionTable from '../../components/tables/TransactionTable';

import './data.css';

import { getTransaction } from '../../actions/Transactions';

export default class Data extends Component {
    constructor(props) {
        super(props);

        this.state = {
            year: 0,
            month: '',
            transactions: [],
            searchForm: false,
            addForm: false,
            editForm: false,
            error: false,
            errorMessage: '',
        };

        this.navBtnClick = this.navBtnClick.bind(this);
        this.addBtnClick = this.addBtnClick.bind(this);
        this.searchBtnClick = this.searchBtnClick.bind(this);
        this.editBtnClick = this.editBtnClick.bind(this);
        this.deleteBtnClick = this.deleteBtnClick.bind(this);
        this.updateTable = this.updateTable.bind(this);
        this.setError = this.setError.bind(this);

        this.months = [
            'January',
            'February',
            'March',
            'April',
            'May',
            'June',
            'July',
            'August',
            'September',
            'October',
            'November',
            'December',
        ];
    }

    componentDidMount() {
        const currentDate = new Date();
        var currentYear = currentDate.getYear() + 1900;
        this.setState({ year: currentYear });
        var currentMonth = this.months[currentDate.getMonth()].toLowerCase();
        this.setState({ month: currentMonth });

        getTransaction({ year: currentYear, month: currentMonth }).then((res) => {
            if (res.error) {
                this.setError(true, res.error);
            } else {
                this.setError(false);
                this.setState({ transactions: res });
            }
        });
    }

    navBtnClick() {
        this.props.updateNavBarState();
    }

    addBtnClick(e) {
        this.setState({ addForm: !this.state.addForm });
    }

    searchBtnClick() {
        this.setState({ searchForm: !this.state.searchForm });
    }

    editBtnClick(e) {
        this.setState({ editForm: !this.state.editForm });
    }

    deleteBtnClick(e) {}

    updateTable(transactions) {
        // If there isn't an error, close the form
        if (this.state.error === false) {
            this.setState({ transactions: transactions });
            this.setState({ addForm: false });
            this.setState({ searchForm: false });
            this.setState({ editForm: false });
        }
    }

    setError(state, message = '') {
        this.setState({ error: state });
        this.setState({ errorMessage: message });
    }

    render() {
            return (
                <Fragment>
                    <SideBar sideBarState={this.props.sideBarState} />
                    <div className="page">
                        <div className="grid head">
                            <span id="sidebarCollapseBtn">
                                <i className="fas fa-align-left" onClick={this.navBtnClick}></i>
                            </span>
                            <h1 className="capitalize">data</h1>
                        </div>
                        <div className="content">
                            <div className="card" id="dataCard">
                                <div className="actions" id="actions">
                                    <div className="flex">
                                        // This if statement
                                        {this.state.searchForm === true ? (
                                            <button
                                                className="search btn"
                                                id="searchBtn"
                                                onClick={this.searchBtnClick}
                                            >
                                                close
                                            </button>
                                        ) : (
                                            <button
                                                className="search btn"
                                                id="searchBtn"
                                                onClick={this.searchBtnClick}
                                            >
                                                <i className="fas fa-search mr-025"></i>search
                                            </button>
                                        )}
                                        <button
                                            className="add btn"
                                            id="addBtn"
                                            onClick={this.addBtnClick}
                                        >
                                            <i className="fas fa-plus mr-025"></i>add
                                        </button>
                                    </div>
                                    {this.state.searchForm ? (
                                        <SearchForm
                                            year={this.state.year}
                                            month={this.state.month}
                                            updateTable={this.updateTable}
                                            setError={this.setError}
                                        />
                                    ) : (
                                        <Fragment />
                                    )}
                                </div>
                                <div className="output">
                                    {this.state.transactions.length > 1 ? (
                                        <TransactionTable transactions={this.state.transactions} />
                                    ) : (
                                        <Fragment />
                                    )}
                                </div>
                            </div>
                        </div>
                    </div>
                </Fragment>
            );
    }
}

Thanks in advance, Marc

Advertisement

Answer

A couple suggestions I would make about this code:

  1. A somewhat personal preference, using arrow notation to define class methods so you don’t have to .bind(this) for every one.
// this is the same as
constructor(props) {
  this.someFunc = this.someFunc.bind(this)
}
someFunc() {}

// writing just this
someFunc = () => {}
  1. The code inside your if (this.state.error) {} is almost identical to the entire component with some minor changes. I would suggest being more targeted / specific with your if statements and just change the smallest piece needed. (see large code blow below)

  2. In a couple places you are using a ternary operator to return something OR a <Fragment />. Again, this might just be personal preference, but you could instead just use && to simplify the code some.

// this is the same as
{this.state.searchForm ? (
  <MyComponent />
) : (
  <Fragment />
)}

// is the same as writing
{this.state.searchForm && <MyComponent />}

// or
{this.state.searchForm && (
  <MyComponent
    foo="something"
    bar="baz"
    onClick={this.onClick}
  />
)}

Here is your full code sample with the simplifications from above applied.

RE: your actual question though, about why the text isn’t swapping out inside your search button… your click handler looks correct and should be changing the state properly… Maybe having the if statement like I suggested, be more targeted to only changing the actual text inside the button instead of the whole button will help.

import React, { Component, Fragment } from "react";

import SideBar from "../../components/navBar/SideBar";
import SearchForm from "../../components/forms/SearchForm";
import TransactionTable from "../../components/tables/TransactionTable";

import "./data.css";

import { getTransaction } from "../../actions/Transactions";

export default class Data extends Component {
  constructor(props) {
    super(props);

    this.state = {
      year: 0,
      month: "",
      transactions: [],
      searchForm: false,
      addForm: false,
      editForm: false,
      error: false,
      errorMessage: "",
    };

    this.months = [
      "January",
      "February",
      "March",
      "April",
      "May",
      "June",
      "July",
      "August",
      "September",
      "October",
      "November",
      "December",
    ];
  }

  componentDidMount() {
    const currentDate = new Date();
    var currentYear = currentDate.getYear() + 1900;
    this.setState({ year: currentYear });
    var currentMonth = this.months[currentDate.getMonth()].toLowerCase();
    this.setState({ month: currentMonth });

    getTransaction({ year: currentYear, month: currentMonth }).then((res) => {
      if (res.error) {
        this.setError(true, res.error);
      } else {
        this.setError(false);
        this.setState({ transactions: res });
      }
    });
  }

  navBtnClick = () => {
    this.props.updateNavBarState();
  };

  addBtnClick = (e) => {
    this.setState({ addForm: !this.state.addForm });
  };

  searchBtnClick = () => {
    this.setState({ searchForm: !this.state.searchForm });
  };

  editBtnClick = (e) => {
    this.setState({ editForm: !this.state.editForm });
  };

  deleteBtnClick = (e) => {};

  updateTable = (transactions) => {
    // If there isn't an error, close the form
    if (this.state.error === false) {
      this.setState({ transactions: transactions });
      this.setState({ addForm: false });
      this.setState({ searchForm: false });
      this.setState({ editForm: false });
    }
  };

  setError = (state, message = "") => {
    this.setState({ error: state });
    this.setState({ errorMessage: message });
  };

  render() {
    return (
      <Fragment>
        <SideBar sideBarState={this.props.sideBarState} />
        <div className="page">
          <div className="grid head">
            <span id="sidebarCollapseBtn">
              <i className="fas fa-align-left" onClick={this.navBtnClick}></i>
            </span>
            <h1 className="capitalize">data</h1>
          </div>
          <div className="content">
            <div className="card" id="dataCard">
              <div className="actions" id="actions">
                <div className="flex">
                  <button
                    className="search btn"
                    id="searchBtn"
                    onClick={this.searchBtnClick}
                  >
                    {this.state.searchForm ? (
                      "close"
                    ) : (
                      <Fragment>
                        <i className="fas fa-search mr-025"></i>search
                      </Fragment>
                    )}
                  </button>
                  <button
                    className="add btn"
                    id="addBtn"
                    onClick={this.addBtnClick}
                  >
                    <i className="fas fa-plus mr-025"></i>add
                  </button>
                </div>
                {this.state.searchForm && (
                  <SearchForm
                    year={this.state.year}
                    month={this.state.month}
                    updateTable={this.updateTable}
                    setError={this.setError}
                  />
                )}
              </div>
              <div className="output">
                {this.state.error && <h2>{this.state.errorMessage}</h2>}
                {this.state.transactions.length > 1 && (
                  <TransactionTable transactions={this.state.transactions} />
                )}
              </div>
            </div>
          </div>
        </div>
      </Fragment>
    );
  }
}
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement