OLA
OLA

Reputation: 971

REACT Component not returning axios data

I'm new to REACT and learning a ton. I am trying to retrieve my data from a SharePoint list and render it to a page as a table but when I make my axios call, I get the following error. tblData is undefined I know why I get the error and it's because the this in the axios is different from the outside, so I turned it into an arrow function and it still didn't work. I then assigned the outer this to a variable and used it in the axios scope but that still didn't work. Please help with!!

function Table(props) {

  return (
    <tr>
        <td>{props.title}</td>
        <td>{props.fname}</td>
        <td>{props.lname}</td>
        <td>{props.phone}</td>
        <td>{props.age}</td>
    </tr>
   )

 }

function App() {
  var endPointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbyTitle('Axios List')/items";
  var tbl = this;
  axios.get(endPointUrl).then(response => {
    tbl.tblData = response.data.value.map(function (data) {
        return (
            <Table
                title={data.Title}
                fname={data.FirstName}
                lname={data.LastName}
                phone={data.Phone}
                age={data.age}
            />
        )
    })
 })
  return (
    { tblData }
 )
}

ReactDOM.render(
  <App />,
  document.getElementById("app")
)

Any help would be much appreciated.

When I console.log(response.data.value), I get enter image description here

Upvotes: 0

Views: 279

Answers (1)

Milos Mosovsky
Milos Mosovsky

Reputation: 2983

Fundamentals

At first you should understand the fundamentals of React and thus that functional components are not just normal functions where you can mutate this scope and it will be magically available in the render methods.

React operates against virtual DOM and diffing is being done when it is needed (when state changes) but state !== this.

More about lifecycle of components is here https://reactjs.org/docs/state-and-lifecycle.html

Why the codesandbox works

In your comments you linked https://codesandbox.io/s/render-styled-table-with-data-iou7k?file=/components/App.js which works, and it works because of simple reason, there is no another lifecycle of component. Data is static and not asynchronous and on first render it works with this.

However when you are fetching data from API you are making asynchronous code through promises https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

When you work with promises react component needs to be "informed" that it should re-rerender the DOM

Solution - use component state (hooks)

function Table(props) {

  return (
    <tr>
        <td>{props.title}</td>
        <td>{props.fname}</td>
        <td>{props.lname}</td>
        <td>{props.phone}</td>
        <td>{props.age}</td>
    </tr>
   )

 }

function App() {
  const [data, setData] = React.useState()

  var endPointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbyTitle('Axios List')/items"

  React.useEffect(() => {
    axios.get(endPointUrl).then(response => setData(response.data))
  }, [])

  return (
    <React.Fragment>
      {data && data.value.map(_data => (
        <Table
                title={_data.Title}
                fname={_data.FirstName}
                lname={_data.LastName}
                phone={_data.Phone}
                age={_data.age}
            />
       )}
    </React.Fragment>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById("app")
)

Explanation

Now your component will enter a several lifecycle states:

  1. First render will be with data undefined and return ( data && ) condition will evaluate to false which will render nothing.
  2. Component will mount and by using React.useEffect we will trigger loading of data https://reactjs.org/docs/hooks-effect.html
  3. We will set component state with setData which will trigger react reconciliation and re-rendering and data will be accessible.

Upvotes: 1

Related Questions