0

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

7
  • What you are getting in 'response '. Console the result to confirm please. Commented Apr 18, 2020 at 23:45
  • 1
    Functional components have are instanceless, there is no this. You need to use some component state, i.e. const [tbl, setTbl] = useState({ tblData: []}) Commented Apr 18, 2020 at 23:50
  • I added the image I get when I console.log the response Commented Apr 18, 2020 at 23:51
  • @DrewReese, I don't understand what you mean. Are you suggesting to use a class component Commented Apr 18, 2020 at 23:52
  • Image looking pretty messy. console it in such a way that show 'data' - title, firstName, Phone. Commented Apr 18, 2020 at 23:53

1 Answer 1

1

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.
Sign up to request clarification or add additional context in comments.

3 Comments

Is const [data, setData] = React.useState() the same as const {data, setData} = React.useState()?
I get an error on what you provided. 'endpointUrl' is undefined.
@OLA I edited the answer, there was only lowercase problem. And regarding the question, no, it's not I advice you to read developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… about destructuring, one which I used is for array, yours is for objects.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.