Ali
Ali

Reputation: 485

How to assign value onClick from different component to another component in React

What i want to do :

How do i achieve the desired behaviour pls help

App.js

import React, { useState } from 'react';
import './App.css'
import Episodes from './components/Episodes/Episodes'
import CustomNavbar from './components/Navbar/Navbar'
import Pagination from './components/Pagination/Pagination'
function App() {

  const [postsPerPage] = useState(20);
  const [currentPage, setCurrentPage] = useState(1);

  const url=`https://rickandmortyapi.com/api/episode?page=${currentPage}`
  let urlQuery = `https://rickandmortyapi.com/api/episode?name=${SEARCH TEXT HERE}`

  const paginate = pageNumber => setCurrentPage(pageNumber);

  return (
    <div>
      <CustomNavbar />
      <Episodes
      urlQuery={urlQuery}
      url={url}
      />
      <Pagination
        postsPerPage={postsPerPage}
        totalPosts={36}
        paginate={paginate}
      />
    </div>
  );
}

export default App;

Navbar.js

import React from 'react';
import Navbar from 'react-bootstrap/Navbar';
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import FormControl from 'react-bootstrap/FormControl';

const customNavbar = () => {

  return (
    <Navbar bg="light" expand="lg">
      <Navbar.Brand href="#home">Rick And Morty</Navbar.Brand>
      <Form inline>
        <FormControl type="text" placeholder="Search" />
        <Button>Search</Button>
      </Form>
    </Navbar>
  );
}
export default customNavbar

Edit

On Zohaib's suggestion this error is thrown

Failed to compile.

./src/components/Navbar/Navbar.js
  Line 14:48:  Unexpected use of 'event'  no-restricted-globals

Search for the keywords to learn more about each error.   

Upvotes: 1

Views: 1541

Answers (4)

3limin4t0r
3limin4t0r

Reputation: 21130

There is a React guide about this specific problem: Lifting State Up.

Normally what you do is you manage the state in the parent. In this case App where you manage the search text state. You pass down a function to components to change this state. The components that depend upon this state are passed the value through the properties.

Here is an example:

const {useEffect, useState} = React;

function App() {
  const episodesURL = "https://rickandmortyapi.com/api/episode";
  
  const [page, setPage] = useState(1);
  const [pageInfo, setPageInfo] = useState({});
  const [searchText, setSearchText] = useState("");
  const [episodes, setEpisodes] = useState([]);
  
  useEffect(() => {
    const url = new URL(episodesURL);
    url.searchParams.set("page", page);
    if (searchText) url.searchParams.set("name", searchText);
    
    fetch(url)
    .then(response => response.json())
    .then(response => {
      if (response.error) {
        setPageInfo({});
        setEpisodes([]);
      } else {
        setPageInfo(response.info);
        setEpisodes(response.results);
      }
    });
  }, [page, searchText]);

  const search = searchText => {
    setSearchText(searchText);
    setPage(1);
  };
  
  return (
    <div>
      <CustomNavbar search={search} />
      <Episodes episodes={episodes} />
      <Pagination setPage={setPage} info={pageInfo} />
    </div>
  );
}

function CustomNavbar({search}) {
  const [searchText, setSearchText] = useState("");
  
  const handleFormSubmit = event => {
    event.preventDefault();
    search(searchText);
  };
  
  return (
    <form onSubmit={handleFormSubmit}>
      <input
        type="text"
        placeholder="search"
        value={searchText}
        onChange={event => setSearchText(event.target.value)}
      />
      <button type="submit">Search</button>
    </form>
  );
}

function Episodes({episodes}) {  
  return (
    <table>
      <thead>
        <tr>
          <th>episode</th>
          <th>name</th>
          <th>air date</th>
        </tr>
      </thead>
      <tbody>
        {episodes.map(episode => (
          <tr key={episode.id}>
            <td>{episode.episode}</td>
            <td>{episode.name}</td>
            <td>{episode.air_date}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

function Pagination({setPage, info}) {
  return (
    <div>
      {info.prev && <a onClick={() => setPage(page => page - 1)}>previous</a>}
      {info.next && <a onClick={() => setPage(page => page + 1)}>next</a>}
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
th { text-align: left; }
a { cursor: pointer; }
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

Upvotes: 1

radihuq
radihuq

Reputation: 1082

App.js

import React, { useState, useEffect } from 'react';
import './App.css'
import Episodes from './components/Episodes/Episodes'
import CustomNavbar from './components/Navbar/Navbar'
import Pagination from './components/Pagination/Pagination'
function App() {

  const [postsPerPage] = useState(20);
  const [currentPage, setCurrentPage] = useState(1);
  const [userSearchValue, setUserSearchValue] = useState('');

  const [url, setUrl] = useState(``);
  const [urlQuery, setUrlQuery] = useState(``)

  useEffect(() => {
    setUrl(`https://rickandmortyapi.com/api/episode?page=${currentPage}`)
  }, [currentPage]);

  useEffect(() => {
    setUrlQuery(`https://rickandmortyapi.com/api/episode?name=${userSearchValue}`)
  }, [userSearchValue])

  const paginate = pageNumber => setCurrentPage(pageNumber);

  const handleButtonClick = (searchValue) => {
      setUserSearchValue(searchValue);
  }

  return (
    <div>
      <CustomNavbar
      onButtonClick={handleButtonClick}
      />
      <Episodes
      urlQuery={urlQuery}
      url={url}
      />
      <Pagination
        postsPerPage={postsPerPage}
        totalPosts={36}
        paginate={paginate}
      />
    </div>
  );
}

export default App;

Navbar.js

import React, { useState } from 'react';
import Navbar from 'react-bootstrap/Navbar';
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import FormControl from 'react-bootstrap/FormControl';

const customNavbar = ({ onButtonClick }) => {

    const [searchValue, setSearchValue] = useState('');

  return (
    <Navbar bg="light" expand="lg">
      <Navbar.Brand href="#home">Rick And Morty</Navbar.Brand>
      <Form inline>
        <FormControl type="text" placeholder="Search" value={searchValue} onChange={(e) => setSearchValue(e.target.value)} />
        <Button onClick={() => onButtonClick(searchValue)}>Search</Button>
      </Form>
    </Navbar>
  );
}
export default customNavbar

The important part here is you're passing down the handleButtonClick function to the child component (Navbar). This way you can call that parent function in the child component whenever you want (ie. when the user clicks the submit button).

Upvotes: 1

Vahid Alimohamadi
Vahid Alimohamadi

Reputation: 5858

Do you mean something like this?

Upvotes: 1

Zohaib Sohail
Zohaib Sohail

Reputation: 310

Change urlQuery to state variable. Then, pass setUrlQuery to NavBar as a prop and on search button clickEvent call setUrlQuery function.

Upvotes: 0

Related Questions