0

I have functions.js file and it export one function that I want to use in many files.

functions.js

import { API_URL } from "./index";

export const getData = (skip = 0, params = "") => {
  this.setState({
    loading: true
  });

  fetch(`${API_URL}items?limit=5&skip=${skip}${params}`, {
    method: "GET",
    credentials: "include"
  })
    .then(res => res.json())
    .then(res => {
      if (res.result.length > 0) {
        let array = [];

        res.result.map(item => {
          let obj = item.data;
          obj = Object.assign({ id: item._id }, obj);
          array.push(obj);
        });
        
        this.setState({
          records: array,
          loading: false
        });
      } else {
        this.setState({
          next: true,
          loading: false,
          records: []
        });
      }
    })
    .catch(err => {
      this.setState({
        loading: false
      });
    });
};

hear this is function.js file that gets data from API and set in the state, now, I want to use this function in items.js

items.js

import { getData } from "./../../config/functions";
import React from "react";

class Customers extends React.Component {

 constructor(props) {
    super(props);
    this.getData = getData.bind(this);
 }

 componentDidMount() {
    this.getData();
 }
 
 ...

}

Error

TypeError: Cannot read property 'setState' of undefined

I fount this answer How to use state of one component in another file in reactjs? but it did not work for me so help me to change app.js file state from my functions.js file.

Mitesh K
  • 694
  • 1
  • 11
  • 24

1 Answers1

3

You're trying to re-bind this on an arrow function, which you cannot do. Check out this other SO question/answer for more details, but that's your problem. I'm going to edit this post with a suggestion of a more idiomatic way to write this in React.

Edit: OK I wanted to get you an answer quickly so you could unblock yourself and learn a bit more about arrow functions and this binding.

But more than just fixing this, you could improve this code significantly if you separate your api requests from your component. Right now you're mixing them up by trying to set state in your function that fetches data.

import { API_URL } from "./index";

export const getData = (skip = 0, params = "") => {
  this.setState({
    loading: true
  });

  fetch(`${API_URL}items?limit=5&skip=${skip}${params}`, {
    method: "GET",
    credentials: "include"
  })
    .then(res => res.json())
    .then(res => {
      // no need to declare an array and then push to it,
      // that's what map is for. It will return a new array.
      return res.result.map(item => {
        // can also be written as return { ...item, id: item._id }
        return Object.assign({ id: item._id }, obj)
      });
    });
    // no need to catch here, you can do error handling in your component
};



import { getData } from "./../../config/functions";
import React from "react";

class Customers extends React.Component {

 constructor(props) {
    super(props);
    this.fetchData = this.fetchData.bind(this);
 }

 componentDidMount() {
    this.fetchData();
 }

 fetchData() {
    getData()
      .then((results) => {
        this.setState({
          next: results.length === 0,
          records: results,
          loading: false
        });
       })
       .catch((err) => {
         this.setState({ loading: false })
       });
 }
 
 ...

}
Matthew Brooks
  • 521
  • 2
  • 5
  • is any other way to setState in the functions.js file ?? – Mitesh K Nov 28 '20 at 11:20
  • 1
    Yes, by not using arrow functions. From there, you can use `bind` like you were, but you cannot use arrow functions and use `this` to get access to the values you want, _unless the correct this value is available in a parent scope at definition time_. However, this is not a good design for your code. Why? For one, if I look at the component definition, I cannot see what's happening. I have to go to a different file to see that state is being set. It's also difficult to test. There are more reasons, but I'll stop there. Please consider the approach I've posted. – Matthew Brooks Nov 28 '20 at 11:24