0

Goal

Been stuck on this for good few hours now. I need help in implementing a way of refreshing the data when a user submits the form.

Code

This is the main component that laods both the ProductForm and ShowProducts components.

import React from 'react';
import './App.css';
import { ShowProducts } from './ShowProducts';
import { ProductForm  } from './ProductsForm';


class App extends React.Component {
  render() {
    return (
      <div className="App">
        <ProductForm/>
        <ShowProducts />
      </div>
    );
  }
}

export default App;

Here is the ProductsForm file, all works fine as it should. It sends data to NodeJS to insert values into a database.

import React from 'react';
import axios from 'axios';

class ProductForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            productName: '',
            stock: '',
            basePrice: ''
        }
    }

    changeHandler = e => {
        this.setState({ [e.target.name]: e.target.value });
    }

    submitHandler = e => {
        e.preventDefault();
        console.log(this.state);
        axios.post('http://localhost:5000/addProduct', this.state)
            .then(res => {
                console.log(res);
            })
            .catch(err => {
                console.log(err);
            })
    }

    render() {
        const { productName, stock, basePrice } = this.state;
        return (
            <form onSubmit={this.submitHandler}>

                <input
                    placeholder="Product Name"
                    value={productName}
                    name="productName"
                    onChange={this.changeHandler} />

                <input
                    placeholder="Stock"
                    value={stock}
                    name="stock"
                    onChange={this.changeHandler} />

                <input
                    placeholder="Price"
                    value={basePrice}
                    name="basePrice"
                    onChange={this.changeHandler} />
                <button type="submit">Submit</button>
            </form>
        );
    }
}

export {ProductForm};

Finally, here I have ShowProducts. This component communicates with NodeJS to fetch the data form the database and displays it.

import React from 'react';

class ShowProducts extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          products: []
        };
        this.componentDidMount = this.componentDidMount.bind(this);
    }
    
    componentDidMount() {
        fetch('http://localhost:5000/')
            .then(res => res.json())
            .then(res => this.setState({products : res}, console.log(res)));
        }

    render() {
        return (
          <div className="App">
              {this.state.products.map((product, i) => (
                <div  key={i}>
                   <p style={{fontSize: "12px"}}>Product: {product.product_name} - Stock: {product.stock}</p>
                </div>
              ))}
             
          </div>
        );
      }
}

export { ShowProducts };

What I have tried

I added this function in the ShowProducts.

updateData() {
    fetch('http://localhost:5000/')
    .then(res => res.json())
    .then(res => this.setState({products : res}, console.log(res)));
}

And altered the render to this:

render() {
    return (
      <div className="App" onClick={this.updateData()}>
...

      </div>
    );
  }

And finally in the ProductsForm I have altered the button to this:

<button type="submit" onClick={this.props.updateData}>Submit</button>

Problem

This works, but it creates an infinite loop somewhere - because my Chrome Console is going crazy.. not sure why.

Eduards
  • 1,734
  • 2
  • 12
  • 37

2 Answers2

1

React does not know when your Db gets updated. To let it know, either change state or props for a re-render. so, inside your submitHandler

axios.post('http://localhost:5000/addProduct', this.state)
      .then(res => {
        console.log(res);
        // .... here fetch data again from backend and set to state, like: 
        /* fetch('http://localhost:5000/')
            .then(res => res.json())
            .then(res => this.setState({products : res}, console.log(res)));
        } */
      })

This way your state will change, which cause component to re-render

Shivam Jha
  • 3,160
  • 3
  • 22
  • 36
1

Thanks to https://stackoverflow.com/users/11667949/shivam-jha I managed to solve this.

I moved all the loading logic into App.js

import React from 'react';
import './App.css';
import { ShowProducts } from './ShowProducts';
import { ProductForm } from './ProductsForm';


class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      products: []
    };
    this.componentDidMount = this.componentDidMount.bind(this);
  }

  componentDidMount() {
    fetch('http://localhost:5000/')
      .then(res => res.json())
      .then(res => this.setState({ products: res }, console.log(res)));
  }

  render() {
    return (
      <div className="App">
        <ProductForm handler={this.componentDidMount} />
        <ShowProducts products={this.state.products}/>
      </div>
    );
  }
}

export default App;

Altered the ShowProducts.js to get data from the parent (App.js)

import React from 'react';

class ShowProducts extends React.Component {
    loadData() {
        return (
            <div>
                {this.props.products.map((product, i) => (
                    <div key={i}>
                        <p style={{ fontSize: "12px" }}>Product: {product.product_name} - Stock: {product.stock}</p>
                    </div>
                ))}
            </div>
        )
    }

    render() {
        return (
            <div className="App">
                {this.loadData()}
            </div>
        );
    }
}

export { ShowProducts };

And finally the one I was after...

import React from 'react';
import axios from 'axios';

class ProductForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            productName: '',
            stock: '',
            basePrice: ''
        }
    }

    changeHandler = e => {
        this.setState({ [e.target.name]: e.target.value });
    }

    submitHandler = e => {
        e.preventDefault();
        console.log(this.state);
        axios.post('http://localhost:5000/addProduct', this.state)
            .then(res => {
                console.log(res);
            })
            .catch(err => {
                console.log(err);
            })
    }

    render() {
        const { productName, stock, basePrice } = this.state;
        return (
            <form onSubmit={this.submitHandler}>

                <input
                    placeholder="Product Name"
                    value={productName}
                    name="productName"
                    onChange={this.changeHandler} />

                <input
                    placeholder="Stock"
                    value={stock}
                    name="stock"
                    onChange={this.changeHandler} />

                <input
                    placeholder="Price"
                    value={basePrice}
                    name="basePrice"
                    onChange={this.changeHandler} />
                <button type="submit" onClick={this.props.handler}>Submit</button>
            </form>
        );
    }
}

export {ProductForm};
Eduards
  • 1,734
  • 2
  • 12
  • 37