简体   繁体   中英

React not able to setState from within a function

I'm trying to convert a class-based component to a functional component. I believe I have the fundamentals for functional-based components in place, but for some reason, useState is not flipping the boolean value when the button is clicked.

Working code:

import React, { Component } from "react";
import ReactDOM from "react-dom";
import BootstrapTable from "react-bootstrap-table-next";
import "bootstrap/dist/css/bootstrap.min.css";
import "react-bootstrap-table-next/dist/react-bootstrap-table2.min.css";
import "./styles.css";
import { Button } from "react-bootstrap";

const products = [
  { id: 1, name: "Item 1", price: 100 },
  { id: 2, name: "Item 2", price: 102 }
];

class App extends Component {
  constructor() {
    super();
    this.state = {
      // For displaying data
      columns: [
        {
          dataField: "id",
          text: "id",
          sort: true
        },
        {
          dataField: "name",
          text: "Name",
          sort: true
        },
        {
          dataField: "price",
          text: "Product Price"
        },
        {
          dataField: "follow",
          text: "Follow",
          formatter: this.linkFollow,
          sort: true
        }
      ],
      isFollow: true
    };

    this.onFollowChanged.bind(this);
  }

  onFollowChanged() {
    this.setState({ isFollow: !this.state.isFollow });
    console.log(this.state.isFollow);
  }

  linkFollow = (cell, row, rowIndex, formatExtraData) => {
    return (
      <Button
        onClick={() => {
          this.onFollowChanged(row);
        }}
      >
        Follow
      </Button>
    );
  };

  render() {
    return (
      <div style={{ padding: "20px" }}>
        <h1 className="h2">Products</h1>
        <BootstrapTable
          keyField="id"
          data={products}
          columns={this.state.columns}
        />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Working demo in sandbox

Non-Working Code:

import React, { useState } from "react";
import BootstrapTable from "react-bootstrap-table-next";
import "bootstrap/dist/css/bootstrap.min.css";
import "react-bootstrap-table-next/dist/react-bootstrap-table2.min.css";
import { Button } from "react-bootstrap";

export default function App() {
  function onFollowChanged() {
    setIsPresent(!isPresent);
    console.log(isPresent);
  }

  let buttonFollow = (cell, row, rowIndex, formatExtraData) => {
    return <Button onClick={() => onFollowChanged(row)}>Present</Button>;
  };

  const [isPresent, setIsPresent] = useState(true);

  const students = [
    {
      id: 100,
      fName: "John",
      lName: "Doe",
      grade: "first"
    },
    {
      id: 200,
      fName: "Jane",
      lName: "Doe",
      grade: "second"
    },
    {
      id: 300,
      fName: "Peter",
      lName: "Paker",
      grade: "third"
    },
    {
      id: 400,
      fName: "Clark",
      lName: "Kent",
      grade: "fourth"
    },
    {
      id: 500,
      fName: "LeBron",
      lName: "James",
      grade: "fifth"
    }
  ];

  const columns = [
    {
      dataField: "id",
      text: "id",
      sort: true
    },
    {
      dataField: "fName",
      text: "First Name",
      sort: true
    },
    {
      dataField: "lName",
      text: "Last Name"
    },
    {
      dataField: "grade",
      text: "Grade",
      sort: true
    },
    {
      dataField: "present",
      text: "Present",
      formatter: buttonFollow
    }
  ];

  return (
    <div>
      <BootstrapTable keyField="id" data={students} columns={columns} />
    </div>
  );
}

With my code, when I click the "Present" button the console log keeps printing the initial value of isPresent . I'm expecting it to toggle between true/false.

Non-working demo in sandbox.

You are nearly there, I grabed your code from the sandbox :

  const [isPresent, setIsPresent] = useState(true);

  function toggleValue() {
    setIsPresent(!isPresent);
    console.log(isPresent);
  }

  return (
    <div>
      <BootstrapTable keyField="id" data={students} columns={columns} />
      <button onClick={toggleValue}>Test</button>
      {isPresent ? "true" : "false"} // conditional render string value
    </div>
  );

Resource recommendation: React beta docs

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM