Ben Parsonage
Ben Parsonage

Reputation: 23

Passing state Array to child components in React

I'm trying to pass two array variables to a child component in react. I know it's something simple and I'm being stupid but I jest need a hand.

I make two API calls in two components that are in the same file. They should be adding the iterable data into the variable using the set methods. By the time the call to the component comes, the variables are undefined.

What am I doing wrong?

const ShowResults = props => {

  const { pk } = props;


  const [attributionsData, setAttributionsData] = useState([])
  const [interactionsData, setInteractionsData] = useState([])

  function ListAttributions({ pk }) {
    const { loading, error, data } = useQuery(GET_ATTRIBUTIONS, {
        variables: { pk },
    });
    if ( loading ) return <h2>LOADING... </h2>;
    if ( error ) return `Error! ${error}`;
    if ( data !== undefined){
      setAttributionsData(data.listAttributions.items);
      return <div>
      {attributionsData.map(({ sk, nominal, organisation, attribution, file_name, datetime_added, exhibit }, index) => (
        <AttributionsCard 
          key={index}
          Sk={sk}
          Nominal={nominal}
          Organisation={organisation}
          Attribution={attribution}
          FileName={file_name}
          FoundInsidePhone={file_name.match(/[0-9]+/g)}
          DateTimeAdded={datetime_added}
          Exhibit={exhibit}
          Pk ={pk}
        />
        ))}
      </div>
    }
  }

  function ListInteractions({ pk }) { //Aug 2022 - This is a working prototype of the query behavious i'm looking for. 
    const { loading, error, data } = useQuery(GET_INTERACTIONS, {
      variables: { pk },
    });
    

    if ( loading ) return <h2>LOADING... </h2>;
    if ( error ) return `Error! ${error}`;
    if ( data !== undefined){
      console.log("Interactions Data - " + data );
      setInteractionsData(data.listInteractions.items)
      return <div>
          {interactionsData.map(({ direction, interaction, partner, duration, datetime, exhibit, organisation, file_name, datetime_added }, index) => (
              <InteractionsCard 
                  key={index}
                  Interaction={interaction}
                  Direction={direction}
                  Partner={partner}
                  Duration={duration}
                  DateTime={datetime}
                  Exhibit={exhibit}
                  Organisation={organisation}
                  FileName={file_name}
                  DateTimeAdded={datetime_added}
                  Pk={pk}
              />
          ))}
      </div>
    }
  }

  return (
    <div style={{display: "inline-grid", inlineSize: "max-content", width: "100%"}}>
      {/* <h2>🚀 Quest has identified the following results against {pk}</h2> */}
      <center>
        <ListAttributions pk={pk}/>
        <ListInteractions pk={pk}/>
      </center>
      <br/>
      <br />
      {/* <ShowInteractionsDataGrid pk={pk}/> */}
      {attributionsData !== [] &&
      // Sep 14th 20:42 -  No idea whats going on with this... The ListAttributions components above work fine
        <TabbedResults pk={pk} attributionsData={attributionsData} interactionsData={interactionsData} />
      }
      <br />
      <br />
    </div>
  );

}

ShowResults.propTypes = {
  pk: PropTypes.string
};

export default ShowResults

Upvotes: 1

Views: 523

Answers (1)

James Trickey
James Trickey

Reputation: 1447

a) You cant setSomeState and then use it immediately. It will not be immediately available within that same function. So the first time you try to map you will have the initialiser of the useState. In this case an empty array.

b) You should do the queries in the parent component, and pass them in as props so there is no need to set parent state

c) Its not good to be setting the state of a parent scope like this. You should move the children to different files (or at least outside of the component) and communicate with props and callbacks. You will save yourself a lot of trouble.

d) This will always be true so TabbedResults will always render:

attributionsData !== []

This is because [] makes a new array. You should use:

  attributionsData && attributionsData.length

e) Never set state straight form the render function. Use a useEffect hook to set it based on the change of a property, such as your data suddenly being populated

Upvotes: 1

Related Questions