2

I am trying to build a simple React App with some CRUD connected to a Rails API. The structure of the project is this:

App.js
 -> UserIndex
   --> Form
   --> User
 -> User

I want to send a value (a function) from <App /> to its grandchild (NOT the immediate child) <User />.

This is <App />:

import "./App.css";
import User from "./components/User";
import UserIndex from "./components/UserIndex";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { useState, createContext } from "react";

export const UserContext = createContext();

function App() {
  const [user, setUser] = useState({});

  // function handleShow() {
  //   console.log("showed!");
  // }
  const handleShow = "fñalksdjfñdlskfjds";

  return (
    <div>
      <UserContext.Provider value={handleShow}>
        <BrowserRouter>
          <Routes>
            <Route path="/" element={<UserIndex />}></Route>

            <Route
              path="users/:userId"
              element={<User id={1} name={"hey"} email={"there"} />}
            />
          </Routes>
        </BrowserRouter>
      </UserContext.Provider>
    </div>
  );
}

export default App;

This is <User />:

import React, { useContext } from "react";
import { Link } from "@mui/material";
import axios from "axios";
import UserContext from "../App";

function User(props) {
  const userName = useContext(UserContext);

  console.log(userName);

  return (
    <div className="centerText">
      <Link
        href={`/users/${props.id}`}
        color="inherit"
        onClick={props.handleShow}
      >
        <h4>{props.name}</h4>
        <h4>{props.email}</h4>
      </Link>
      {props.deleteData && <button onClick={props.deleteData}>Delete</button>}
    </div>
  );
}

export default User;

So I created the Context and provided it in <App /> and consumed it in . But when I console.log(userName); it returns undefined.

Am I doing something wrong? Thanks!

josegp
  • 499
  • 6
  • 21

4 Answers4

1
<Route
  path="users/:userId"
  element={<User id={1} name={"hey"} email={"there"} />}
/>

This route has the problem, since there is no provider higher up the tree. When this route renders, <User> will get undefined from useContext(UserContext). The other route should be fine.

To fix this route, make sure your provider is higher up the component tree. For example, a single provider surrounding all of the routes:

return (
  <UserContext.Provider value={handleShow}>
    <div>
      <BrowserRouter>
        <Routes>
          <Route
            path="/"
            element={<UserIndex />}
          />

          <Route
            path="users/:userId"
            element={<User id={1} name={"hey"} email={"there"} />}
          />
        </Routes>
      </BrowserRouter>
    </div>
  </UserContext.Provider>
)
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
  • Thanks for the reply @Nicholas Tower! I did it like that but still getting `undefined` in every route when doing `console.log(UserName)` in ``. If I `console.log(UserContext)` it shows something so it is not like I am not passing anything. Maybe I am consuming it wrong? – josegp May 28 '22 at 23:12
  • When i plug in the code you've shown (with my tweak for the provider) [it's working for me](https://codesandbox.io/s/unruffled-darwin-j0u22r) – Nicholas Tower May 28 '22 at 23:38
  • Thank you for taking your time to test it. I have no clue why it is behaving like that but will try to keep digging into it – josegp May 28 '22 at 23:48
1
value = {[handleShow,user,setUser]}
**and catch like this**
const value = useContext(UserContext);
const handleShow = value[0];
const user = value[1];
const setUser = value[2];
Hazrat Gafulov
  • 318
  • 4
  • 9
1
import "./App.css";
import User from "./components/User";
import UserIndex from "./components/UserIndex";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { useState, createContext } from "react";

export const UserContext = createContext();

function App() {
  const [user, setUser] = useState({});

  const handleShow = "testtest";

  return (
    <div>
        <UserContext.Provider value={handleShow}>
      <BrowserRouter>
        <Routes>
          <Route
            path="/"
            element={<UserIndex />}
          ></Route>

          <Route
            path="users/:userId"
            element={<User id={1} name={"hey"} email={"there"} />}
          />
        </Routes>
      </BrowserRouter>
       </UserContext.Provider>
    </div>
  );
}

export default App;
Hazrat Gafulov
  • 318
  • 4
  • 9
0

It was the way I was importing the UserContext. Instead of: import UserContext from "../App"; change to: import { UserContext } from "../App";

josegp
  • 499
  • 6
  • 21