Home > Net >  Need to pass props from child to parent in React Firebase app
Need to pass props from child to parent in React Firebase app

Time:01-31

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?

CodePudding user response:

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

CodePudding user response:

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) 
  }}
  • Related