简体   繁体   中英

React - How to pass returned data from an exported function to a component?

How can I pass data I receive from a get request pass over to a component? Whatever I tried wouldn't work but my thinking was as the code below shows.. Thanks!

    export function data() {
        axios.get('www.example.de')
            .then(function(res) {
                return res.data
            })
            .then(function(data) {
                this.setState({
                    list: data
                })
            })
    }

    import {data} from './api.js';

    class Test extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                list: ""
            };
        }

        componentWillMount() {
            data();
        }
        render() {
            return <p > this.state.list < /p>
        }
    }

You call this.setState inside of data()->then callback, so this is context of the then callback function. Instead you should use arrow functions (it does not have its own context) and pass component's this to data function using call

export function data() {
    axios.get('www.example.de')
        .then(res => res.data)
        .then(data => {
            this.setState({
                list: data
            })
        })
}

import {data} from './api.js';

class Test extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            list: ""
        };
    }

    componentWillMount() {
        data.call(this);
    }
    render() {
        return <p > this.state.list < /p>
    }
}

However, your data services must not know about setState and, event more, expect passing this from react component. Your data service must be responsible for retrieving data from server, but not for changing component state, see Single responsibility principle . Also, your data service can be called from another data service. So your data service should return promise instead, that can be used by component for calling setState .

   export function data() {
       return axios.get('www.example.de')
           .then(res => res.data)
   }

and then

componentWillMount() {
    data().then(data=>{
        this.setState({
            list: data
        })
    });
}

your api shouldn't know anything about your component, you can easily do this with callback , like so -

export function data(callback) {
    axios.get('www.example.de')
        .then(res => callback({ data: res.data }))
        .catch(err => callback({ error: err }));
}

By doing this you can easily unit test your api

So in your Test component, you simply do -

componentWillMount() {
  data(result => {
    const { data, error } = result;
    if (error) {
      // Handle error
      return;
    }

    if (data) {
      this.setState({ list: data });
    }
  });
}

Your request is a promise so you can simply return that from the imported function and use the eventual returned result of that within the component. You only want to be changing the state of the component from within the component.

export function getData(endpoint) {
  return axios.get(endpoint);
}

Note I've changed the name of the function to something more "actiony".

import { getData } from './api.js';

class Test extends React.Component {
  constructor(props) {
    super(props);

    // Your state is going to be an array of things, so
    // initialise it with an array to spare confusion
    this.state = { list: [] };
  }

  // I use ComponentDidMount for fetch requests
  // https://daveceddia.com/where-fetch-data-componentwillmount-vs-componentdidmount/
  componentDidMount() {

    // We've returned a promise from `getData` so we can still use the
    // promise API to extract the JSON, and store the parsed object as the
    // component state
    getData('www.example.de')
      .then(res => res.data)
      .then(list => this.setState({ list }))
  }
}

Your external function doesn't have the correct context of this , so you'll need to call it with the correct context from within the component:

componentWillMount() {
    data.call(this);
}

However, inside the API call, it still won't have the correct this context, so you can set a variable to point to this inside the data() function:

export function data() {
  let that = this;
  axios('http://www.url.com')
    .then(function(res) {
      return res.data
    })
    .then(function(data) {
      that.setState({
        list: data
      })
    })
}

Details of the this keyword

However, it's generally considered better practice to only handle your state manipulation from with the component itself, but this will involve handling the asynchronous nature of the GET request, perhaps by passing in a callback to the data() function.

EDIT: Updated with asynchronous code

//api.js
data(callback){
  axios.get('www.url.com')
    .then(res => callback(res));
}

//component.jsx
componentWillMount(){
  data(res => this.setState({list: res}));
}

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