简体   繁体   中英

React: How to Import and use function to component with setState?

I have some big function methods in my react component and I want to put those functions to separate files, import them with es6 modules system. The problem is that inside those methods I'm changing the state of the parent component with setState method. What is the best way to use function in separate file, import this function and use with simple setstate method?

See the fetchProducts method. I want to import this method from separate file

Here is the code:

import React from 'react'
import Header from '../components/Header'

class Main extends React.Component { 
 constructor(props) {
    super(props)
    this.state = {
        firstDetected: false,
        detected: false,
        products: [],
        selectedProduct: null,
        premiumImage: null,
        productImages: [],
        productPrice: null,
        dataFromServer: null,
        default_gender: null,
        bgImage: null,
        productsExtension: null,
        mediaCdn: null,
        fade: false,
        hello: false,
        helloEnd: false,
        collection: false,
        collectionEnd: false,
        capturedImage: null,
        imageReady: false,
        gender: null,
        waitForEnding: true

    }
 }

 componentWillMount() {
    this.fetchProducts(1)
 }

 fetchProducts = (init) => {
    auth.fetch(`${baseUrlTest}/products/get-user-products?init=${init}`)
        .then(res => {

            if (Object.keys(res).length) {
                console.log(res)
                const productsExtension = res['products.extension']
                const mediaCdn = res['media.cdn']
                const randomProduct = randomize(res['products'])

                this.setState({
                    dataFromServer: res,
                    products: res.products,
                    selectedProduct: randomProduct,
                    default_gender: res.default_gender,
                    bgImage: res['background.image'],
                    productsExtension: productsExtension,
                    mediaCdn: mediaCdn,
                    gender: res.default_gender,
                    premiumImage: mediaCdn + randomProduct.image + '.' + productsExtension.find(k => k === 'jpg'),
                    productPrice: randomProduct.price,
                    productImages: res.products.filter((prod) => {
                        return prod.gender === res.default_gender
                    }).map((prod) => {
                        return prod
                    })

                })

                console.log(res.products)

            }
        })
  }

}

Solution without Redux

  1. We export fetchProduct function as a module
  2. Import into our Main component
  3. Assign fetchProduct into our component

We can't use arrow function for fetchProduct.js As stated in YDKJS - "ES6 arrow-functions use lexical scoping for this binding, which means they adopt the this binding (whatever it is) from its enclosing function call."

fetchProducts.js

// Export the function as a module
export default function fetchProducts(init) {
    auth.fetch(`${baseUrlTest}/products/get-user-products?init=${init}`)
        .then(res => {

            if (Object.keys(res).length) {
                console.log(res)
                const productsExtension = res['products.extension']
                const mediaCdn = res['media.cdn']
                const randomProduct = randomize(res['products'])

                this.setState({
                    dataFromServer: res,
                    products: res.products,
                    selectedProduct: randomProduct,
                    default_gender: res.default_gender,
                    bgImage: res['background.image'],
                    productsExtension: productsExtension,
                    mediaCdn: mediaCdn,
                    gender: res.default_gender,
                    premiumImage: mediaCdn + randomProduct.image + '.' + productsExtension.find(k => k === 'jpg'),
                    productPrice: randomProduct.price,
                    productImages: res.products.filter((prod) => {
                        return prod.gender === res.default_gender
                    }).map((prod) => {
                        return prod
                    })

                })

                console.log(res.products)

            }
        })
  }

Main.js

import React from 'react'
import Header from '../components/Header'
// Import the exported function from fetchProduct.js
import fetchProducts from "../middleware/fetchProduct.js"

class Main extends React.Component { 
 constructor(props) {
    super(props)
    this.state = {
        firstDetected: false,
        detected: false,
        products: [],
        selectedProduct: null,
        premiumImage: null,
        productImages: [],
        productPrice: null,
        dataFromServer: null,
        default_gender: null,
        bgImage: null,
        productsExtension: null,
        mediaCdn: null,
        fade: false,
        hello: false,
        helloEnd: false,
        collection: false,
        collectionEnd: false,
        capturedImage: null,
        imageReady: false,
        gender: null,
        waitForEnding: true
    }
 }
 componentWillMount() {
    // Assign fetchProducts into your Component
    this.fetchProducts = fetchProducts.bind(this);
    // Call fetchProduct() inside your Component
    this.fetchProducts();
 }
}

You can simply return the data from your function then set this data in the state of any component :

fetchProducts = init => {
  return auth
    .fetch(`${baseUrlTest}/products/get-user-products?init=${init}`)
    .then(res => {
      if (Object.keys(res).length) {
        console.log(res);
        const productsExtension = res['products.extension'];
        const mediaCdn = res['media.cdn'];
        const randomProduct = randomize(res['products']);

        return {
          dataFromServer: res,
          products: res.products,
          selectedProduct: randomProduct,
          default_gender: res.default_gender,
          bgImage: res['background.image'],
          productsExtension: productsExtension,
          mediaCdn: mediaCdn,
          gender: res.default_gender,
          premiumImage:
            mediaCdn +
            randomProduct.image +
            '.' +
            productsExtension.find(k => k === 'jpg'),
          productPrice: randomProduct.price,
          productImages: res.products
            .filter(prod => {
              return prod.gender === res.default_gender;
            })
            .map(prod => {
              return prod;
            })
        };
      }
      throw new Error('res has no data');
    });
};

Then use it in a component :

componentDidMount() {
    fetchProducts('initVar').then(res => this.setState(res)).catch(err => console.log(err));
}

First you bind your function scope to its owner component scope.

class Main extends React.Component {
    constructor(props) {
        // {...}
        this.fetchProducts = this.fetchProducts.bind(this);
    }
}

Then you export your component instead of its function, which will allow you to access this function as well as the other members of your component.

export default class Main extends React.Component

Then import it at the beginning of your other scripts/components/tests

import Main from './Main';

And use its function as you see fit

let state = {};
Main.fetchProducts(state);

Or you could just export your function, in case that's the only part of your component you want to access.

class Main extends React.Component {
    // {...}
    export fetchProducts {
        // {...}
    }
}

And then import it in the other scripts

import fetchProducts from './Main';

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