简体   繁体   中英

update UI components when the prop changes in React

I am trying to make an motor cycle social media using React.

when user search for a motorCycle model, it will show all the specs, as well as people who own the motor cycle, so that an user can reach out to them.

So, I am trying to pass all the owners list from a page to OwnersList.jsx as props, so that when the array of owners are ready(after fetching from MongoDB), OwnersList.jsx can show those people on the list.

I want it to show "LOADING..." when the prop array is empty, and as soon as the prop array is ready, I want it to re-render components.

However, even after the array arrives, the page is still showing "LOADING.." and it does't change.

What am I doing wrong here?

Also, that would be great if I can know what kind of basic concepts of React I am missing to be stuck in this kind of bug.

OwnersList.jsx

import React from "react";
import { useEffect, useState } from "react";

export default function OwnersList({ ownerObjectsArray }) {
  useEffect(() => {
    console.log(
      "ownerObjectsArray.length is like this ",
      ownerObjectsArray.length
    );
  }, [ownerObjectsArray]);
  if (ownerObjectsArray.length === 0) {
    console.log("yes, the array is empty. PLEASE WAIT");
    return <h2>Loading...</h2>;
  } else {
    console.log("ownerObjectsArray is not empty, so , i will set it as state.");
    return (
      <div>
        {ownerObjectsArray.map((ownerObject) => {
          return (
            <div key={ownerObject.username}>
              <h3>{ownerObject.username}</h3>
              <button>contact</button>
            </div>
          );
        })}
        OwnersList
      </div>
    );
  }
}

Make use of the ternary operator ( condition ? result : else ) to conditionally render JSX inside of one return statement.

Props changing will trigger a re-render so it will evaluate the ownerObjectsArray.length again, and determine which JSX to render.

Shouldn't need more code than this:

import React from 'react'

export default function OwnersList({ ownerObjectsArray }) {
  return ownerObjectsArray.length ? (
    <div>
      {ownerObjectsArray.map((ownerObject) => (
        <div key={ownerObject.username}>
          <h3>{ownerObject.username}</h3>
          <button>contact</button>
        </div>
      ))}
      OwnersList
    </div>
  ) : (
    <h2>Loading...</h2>
  )
}

There is one gotcha with "props changing". If the reference to the array doesn't change, then the re-render won't be triggered. So if you are just updating the same reference in the parent component, the child doesn't know that the array has changed.

Ex:

const ownerObjectsArray = []
// do some stuff
ownerObjectsArray.push(newObject)

The reference to the variable doesn't change, just one more addition to the same place in memory.

But, to create a new reference to the array, do something like this:

let ownerObjectsArray = []
// do some stuff
ownerObjectsArray = [...ownerObjectsArray, newObject]

Best yet, would be to control the array with useState and pass the state down to the component:

[ownerObjectsArray, setOwnerObjectsArray] = useState([])
// do some stuff
setOwnerObjectsArray((prev) => [...prev, newObject])

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