skip to Main Content

I’m building a React Firebase blog and I want to pass {color} from the ViewPosts component (child) to the App component (parent).

App looks like this:

function App() {

  const [backgroundColor, setBackgroundColor] = useState("");

  return (
    <div className="app" style={{ background: backgroundColor }}>
      <Router>
        <Routes>
          <Route exact path="/" element={<Login />} />
          <Route exact path="/register" element={<Register />} />
          <Route exact path="/reset" element={<Reset />} />
          <Route exact path="/dashboard" element={<Dashboard />} />
          <Route exact path="/view-posts" element={<ViewPosts setBackgroundColor={setBackgroundColor} />} />
          <Route exact path="/create-post" element={<CreatePost />} />
          <Route exact path="/edit-post/:id" element={<EditPost />} />
          <Route exact path="/profile/:id" element={<Profile />} />
        </Routes>
      </Router>
    </div>
  );
}

export default App;

I tried passing the state {setBackgroundColor} to to the ViewPosts component.

This is what ViewPosts looks like:

const ViewPosts = props => {

    const [posts, setPosts] = useState([]);
    const [user, loading, error] = useAuthState(auth);
    const [searchInput, setSearchInput] = useState("");
    const [filteredPosts, setFilteredPosts] = useState([]);

    const [color, setColor] = useState("");

    return (
        <Container>
            <div>
                <div>
                    <h5>Search for a post by keyword</h5>
                    <input
                        id="search-bar"
                        type="text"
                        value={searchInput}
                        onChange={handleSearchChange}
                    />
                </div>
                <input
                    id="search-bar"
                    type="text"
                    value={color}
                    onChange={(e) => setColor(e.target.value)}
                />
                <button
                    className="view-post-button"
                    onClick={() => props.setBackgroundColor(color)}
                >
                    Change background
                </button>
                {sortPosts(filteredPosts).map(post => (
                    <div
                        className="single-post"
                        id={post.id}
                        key={post.id}
                    >
                        <h2
                            className="post-title"
                        >
                            {post.data.title}
                        </h2>
                        <h5>{convertTimestamp(post.data.created)}</h5>
                        <div
                            className="post-body"
                            dangerouslySetInnerHTML={createMarkup(post.data.body)}>
                        </div>
                        <img
                            className="post-image"
                            src={`${post.data.image}`} />
                        <br></br><br></br>
                        <Link to={"/edit-post/" + post.id}>
                            <button
                                className="view-post-button"
                            >
                                Edit
                            </button>
                        </Link>
                        <button
                            className="view-post-button"
                            onClick={() => handleDuplicate(post.id)}
                        >
                            Duplicate
                        </button>
                        <button
                            className="view-post-button"
                            onClick={() => handleDelete(post.id)}
                        >
                            Delete
                        </button>
                    </div>
                ))}
            </div>
        </Container>
    );
};

export default ViewPosts;

I deleted the functions from ViewPosts for the sake of brevity, as I’m only concerned about the following lines in ViewPosts:

                <input
                    id="search-bar"
                    type="text"
                    value={color}
                    onChange={(e) => setColor(e.target.value)}
                />
                <button
                    className="view-post-button"
                    onClick={() => props.setBackgroundColor(color)}
                >

I keep getting the error: Uncaught TypeError: props.setBackgroundColor is not a function.

Can someone help me figure out how to pass {color} from ViewPosts to {setBackgroundColor} in App?

2

Answers


  1. I didn’t get the TypeError. You are on the right track and can definitely pass the setter function directly or use a handler.

    I provided a couple working examples below by extending your sample code to create a minimal reproduction of the question. Hope that helps!

    You can type a color in the input and hit Change color to see the result.

    Solution/Demo

    Using a handler:
    https://codesandbox.io/s/lift-up-state-example-fk78go

    import { useState } from "react";
    
    const ViewPosts = (props) => {
      const [color, setColor] = useState("");
    
      return (
        <div
          style={{
            display: "flex",
            flexDirection: "column",
            border: "2px solid gray",
            padding: "8px"
          }}
        >
          <div>ViewPosts</div>
          <input
            type="text"
            value={color}
            onChange={(e) => setColor(e.target.value)}
          />
          <p>Color: {color}</p>
          <button type="button" onClick={() => props.onColorChange(color)}>
            Change color
          </button>
        </div>
      );
    };
    
    export default function App() {
      const [backgroundColor, setBackgroundColor] = useState("blue");
    
      const handleColorChange = (color) => {
        setBackgroundColor(color);
      };
    
      return (
        <div
          style={{
            display: "flex",
            flexDirection: "column",
            gap: "8px",
            alignItems: "center",
            textAlign: "center",
            border: "2px solid gray",
            padding: "8px"
          }}
        >
          <div>App</div>
          <div
            style={{
              backgroundColor: `${backgroundColor}`,
              height: "40px",
              width: "40px"
            }}
          />
          <ViewPosts onColorChange={handleColorChange} />
        </div>
      );
    }
    

    Passing setter function as prop:
    https://codesandbox.io/s/lift-up-state-pass-setter-as-prop-6jnykp

    import { useState } from "react";
    
    const ViewPosts = (props) => {
      const [color, setColor] = useState("");
    
      return (
        <div
          style={{
            display: "flex",
            flexDirection: "column",
            border: "2px solid gray",
            padding: "8px"
          }}
        >
          <div>ViewPosts</div>
          <input
            type="text"
            value={color}
            onChange={(e) => setColor(e.target.value)}
          />
          <p>Color: {color}</p>
          <button type="button" onClick={() => props.setBackgroundColor(color)}>
            Change color
          </button>
        </div>
      );
    };
    
    export default function App() {
      const [backgroundColor, setBackgroundColor] = useState("blue");
    
      return (
        <div
          style={{
            display: "flex",
            flexDirection: "column",
            gap: "8px",
            alignItems: "center",
            textAlign: "center",
            border: "2px solid gray",
            padding: "8px"
          }}
        >
          <div>App</div>
          <div
            style={{
              backgroundColor: `${backgroundColor}`,
              height: "40px",
              width: "40px"
            }}
          />
          <ViewPosts setBackgroundColor={setBackgroundColor} />
        </div>
      );
    }
    

    Relevant Links/Resources

    Lifting State Up

    Login or Signup to reply.
  2. Everything seems to be correct.

    I think ViewPosts might have been used somewhere else without passing setBackgroundColor, and with just adding question mark or if condition to check if exist, your problem will be solved.

    onClick={() => props?.setBackgroundColor(color)}
    

    or

     onClick={() => {
        if(props.setBackgroundColor)
         props.setBackgroundColor(color) 
      }}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search