1

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
2
  • 1
    Hello again - If my advice was helpful, please think about selecting it as the preferred answer so that others can be helped by it too. Commented Sep 18, 2022 at 19:25
  • 1
    Sorry for the delay. Much appreciated. Commented Sep 26, 2022 at 17:34

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much for your effort on this. Just to clarify... I should alter the logic in the check before calling <TabbedResults /> Encapsulate the List components into different files Pass the queries as props And wrap the calls to setState in a useEffect function? I'll give it a go thank you,
Yes - it is often the case in React that you find logic should actually be moved to the parent. Here you need the data in both parent and child, so why not access it there? It's also often best to bite the bullet and make a new file for your components. It is fine to move chunks of JSX within the same scope for code clarity, but as soon as you start having complex interaction between them you're asking for trouble. Good luck.

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.