1

I created context with null initial value that I am now accessing in other component. However when I destructure it to access the variables form the context then I get ts error:

Property 'users' does not exist on type 'GithubContextProps

function UserResults() {
  const appContext = useContext(GithubContext)

  const { users, loading, fetchUsers } = appContext
  

  useEffect(() => {
    fetchUsers()
  }, [fetchUsers])

  if (!loading) {
    return (
      <div className='grid grid-cols-1 gap-8 xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2'>
        {users.map((user : User) => (
          <UserItem key={user.id} user={user} />
        ))}
      </div>
    )
  } else {
    return <Spinner />
  }
}

And here is where i created context:

export type User = {
  id: number;
  login: string;
  avatar_url: string;
}

interface GithubContextProps {
  users: User[];
  loading: boolean;
  fetchUsers: () => void;
}


const GithubContext = createContext<GithubContextProps | null>(null)

I tried solving this with using conditional checking whether appContext is not null but then useEffect will throw errors that it cannot be used conditionally in this component. Any idea how to solve it without resorting to turning off React strict mode?

3 Answers 3

3

How about:

const { users, loading, fetchUsers } = appContext ?? {};

You'll get undefined when appContext is null.

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

4 Comments

Hmm it seems to solve the issue in question, but I get the issue inside useEffect where the TS error says: Cannot invoke an object which is possibly 'undefined'.
@AlexT Try checking if fetchUsers is available: useEffect(() => { if (fetchUsers) {fetchUsers();} }, [fetchUsers]) or useEffect(() => { fetchUsers?.(); }, [fetchUsers])
Same goes for the users object later in the code as provided in the quetion. Complier will throw an error for it as it possible can be undefined
Same applies in case of users: users?.map(...
0

try with

 const GithubContext = createContext<GithubContextProps | null>({{ users:[], loading:false, fetchUsers:null }});

Comments

0

useEffect, and every other hook must always be called every time the component re-renders, so conditionally calling useEffect will not work. I would try placing the check inside the useEffect then place another check for our jsx:

useEffect(() => {
  if (appContext) appContext.fetchUsers()
}, [fetchUsers])

if (!appContext || appContext.loading) return <Spinner />;
// you can then destructure
const { users, loading, fetchUsers } = appContext;
// ...

Or a more better solution, you can pass the context value as props to <UserResults /> instead so that you'll only need to check on the parent component, which is arguably more cleaner

const Parent = () => {
  const appContext = useContext(GithubContext);
  if (!appContext) return <Spinner />;
  return <UserResults appContext={appContext} />;
}

const UserResults = ({ appContext }) => {
  const { users, loading, fetchUsers } = appContext;
  // ...
}

Comments

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.