Full Stack Development

Context

by Tomas Trescak t.trescak@westernsydney.edu.au

Context

/

Introduction

      import React, { render } from 'react';

function UserInfo({ user }: { user: User }) {
  return <span>{user.name} / {user.uid}</span>
}

function UserPosts({ user }: { user?: User }) {
  return <ul>
    {user.posts.map(i => (
       <li key={i.id}>{i.title}</li>
    ))}
  </ul>
}

function UserDetails({ user }) {
  return (
    <>
      <UserInfo user={user} />
      <UserPosts user={user} />
    </>           
  )
}

export default function App() {
  const user = {
      name: "Tomas",
      uid: 1,
      posts: [
        { id: 1, title: "Post 1" },
        { id: 2, title: "Post 2" },
      ]
  }
  return (
    <UserDetails user={user} />
  );
}

render(<App />)
    

Context

/

Introduction

      import React, { createContext, useContext, useState, render } from 'react';

type Post = {
  id: number;
  title: string;
}

type UserContextType = {
  user: {
    uid: number;
    name: string;
    posts: Post[];
  }
}

// Step 1: Create a Context
const UserContext = 
  createContext<UserContextType | null>(null);

function UserInfo() {
  // Step 3: Consume context
  const { user } = useContext(UserContext);

  return <span>{user.name} / {user.uid}</span>
}

function UserPosts() {
  // Step 3: Consume context
  const { user } = useContext(UserContext);

  return <ul>
    {user.posts.map(i => (
       <li key={i.id}>{i.title}</li>
    ))}
  </ul>
}

function UserDetails() {
  return (
    <>
      <UserInfo />
      <UserPosts />
    </>           
  )
}

export default function App() {
  const user = {
      name: "Tomas",
      uid: 1,
      posts: [
        { id: 1, title: "Post 1" },
        { id: 2, title: "Post 2" },
      ]
  }
  // Step 2: Provide Context
  return (
    <UserContext.Provider value={{ user }}>
      <UserDetails />
    </UserContext.Provider>
  );
}

render(<App />);
    

Context

/

Simplifying Context

      import React, { createContext, useContext, useState, render } from 'react';

type Post = {
  id: number;
  title: string;
}

type UserContextType = {
  login(user: string, password: string),
  logout(),
  user: {
    uid: number;
    name: string;
    posts: Post[];
  } | null
}

// Step 1: Create a Context
const UserContext = 
  createContext<UserContextType | null>(null);

// Step 2: Create custom hook
const useUser = () => {
  return useContext(UserContext);
};

function UserInfo() {
  // Step 3: Consume context
  const { user } = useUser();
  return <span>{user.name} / {user.uid}</span>
}

function UserPosts() {
  // Step 3: Consume context
  const { user } = useUser();

  return <ul>
    {user.posts.map(i => (
       <li key={i.id}>{i.title}</li>
    ))}
  </ul>
}

function UserDetails() {
  const { user } = useUser();
  if (!user) {
    return <div>Not logged in!</div>
  }

  return (
    <>
      <UserInfo />
      <UserPosts />
    </>           
  )
}

function UserProvider({ children }) {
  const [user, setUser] = useState<User | null>(null);

  return (
    <UserContext.Provider value={{
      user,
      async login() {
        // do some login functionality
        setUser({
          name: "Tomas",
          uid: 1,
          posts: [
            { id: 1, title: "Post 1" },
            { id: 2, title: "Post 2" },
          ]
        })
      },
      async logout() {
        setUser(null);
      }}
    }>
      {children}
    </UserContext.Provider>
  )
}

function LoginForm() {
  const { user, login, logout } = useUser();
  return (
    <div>
      { user 
        ? <button onClick={logout}>Logout</button> 
        : <button onClick={login}>Login</button>}
    </div>
  )
}

export default function App() {
  return (
    <UserProvider>
      <LoginForm />
      <UserDetails />
    </UserProvider>
  );
}

render(<App />);