简体   繁体   中英

Pass data between two independent components in ReactJS

I'm building a web-application with ReactJS and that needs me to implement a Search. So far, the search has been implemented (I'm using Fuse.js library for this) using a form with an input element. The form is implemented in the NavBar and after the user types a search-query, he is redirected to 'localhost:3000/search' URL where he can see the results corresponding to his query.

Here is the code I'm using for the form in the SearchBar.

import React, { useState } from 'react';
import { Form, FormControl } from 'react-bootstrap';
import { ReactComponent as SearchLogo } from '../../lib/search-logo.svg';

const SearchBar = () => {
 const [searchQuery, setSearchQuery] = useState({ query: '' });

 const searchQueryHandler = (event) => {
    event.preventDefault();
    setSearchQuery({ query: event.target.value });
 };

 const onFormSubmit = (event) => {
    event.preventDefault();
    window.location.href = "/search";
 }

 return (
    <Form inline className="nav-search-form" onSubmit={onFormSubmit}>
        <SearchLogo className="search-logo" />
        <FormControl
            type="text"
            placeholder="Search spaces of interest"
            className="nav-search"
            value={searchQuery.query}
            onChange={searchQueryHandler} />
    </Form>
 );
}
export default SearchBar;

I need to display the corresponding results in another SearchPage which will take the query from this component after submission and then display the results. Here is the code I have written for it.

import React, { useState, useRef } from 'react';
import { Col, Container, Row } from 'react-bootstrap';
import SpaceCardGrid from '../space-card-grid/space-card-grid';
import useSpaces from '../../utils/firebase/hooks/useSpaces';
import moment, { Moment } from 'moment';
import { roundTime } from '../../utils/date';
import Fuse from 'fuse.js';



const SearchPage = (queries) => {
    const [date, setDate] = useState<[Moment, Moment]>([moment(new Date()), moment(new Date())]);
    const [time, setTime] = useState([roundTime(), roundTime(30)]);
    const [dateRangeType, setDateRangeType] = useState<'week' | 'day' | 'now'>('day');
    const spaceCardGridRef = useRef(null);
    const spaces = useSpaces(dateRangeType, date, time, 0);


    const options = {
        shouldSort: true,
        keys: ['title', 'description'],
    };
    const fuse = new Fuse(spaces, options);
    let filteredspaces = spaces;

    if (queries.query !== '') {
        const result = fuse.search(queries.query);
        console.log(result);
        filteredspaces = [];
        result.forEach((space) => {
            filteredspaces.push(space.item);
        });
    }

    return (
        <div>
            <Container fluid className="bottom-container">
                <Row style={{ justifyContent: 'center', alignItems: 'flex-start' }}>
                    <Col>
                        <div className="grid-root">
                            <SpaceCardGrid spaces={filteredspaces} spaceCardGridRef={spaceCardGridRef} />
                        </div>
                    </Col>
                </Row>
            </Container>
        </div>
    );
};

export default SearchPage;

Just for additional information useSpaces() is a function that gives me all the data (and it does so correctly), and filteredspaces is the final results array that I wish to display on the screen. All these things are perfectly working.

I'm stuck on how to pass the query between the two components though. The queries I have used in SearchPage(queries) is a dummy variable. I'm new to React, and I have learned about Redux, but it seems a lot of work (I might be wrong) for simply passing a value between 2 components. As you can clearly observe, the components aren't related but are independent. Is there a simple way to do this? Any help will be greatly appreciated!

you could use useContenxt along with useReducer hooks for a simpler state structure. I created a small example here . you can find more reference at docs

basically at root from your appplication you would start by creating a context and pass dispatch and query as values to your Provider:

export const QueryDispatch = React.createContext("");
const initialState = { query: "" };

export default function App() {
  const [{ query }, dispatch] = useReducer(queryReducer, initialState);

  return (
    <QueryDispatch.Provider value={{ dispatch, query }}>
      <SearchBar />
      <SearchPage />
    </QueryDispatch.Provider>
  );
}

where queryReducer could be like:

export default function (state, action) {
  switch (action.type) {
    case 'update':
      return {query: action.query};
    default:
      return state;
  }
}

and at any component you could consume from your provider:

at your searchBar

import React, { useContext } from "react";
import { QueryDispatch } from "./App";


const SearchBar = () => {
 const const { dispatch, query } = useContext(QueryDispatch);

 const searchQueryHandler = (event) => {
    dispatch({ type: "update", query: e.target.value })
 };
      ..code

        <FormControl
            type="text"
            placeholder="Search spaces of interest"
            className="nav-search"
            value={query}
            onChange={searchQueryHandler} />

and at your SearchPage

import React, { useContext } from "react";
import { QueryDispatch } from "./App";

const SearchPage = () => {
  const { query } = useContext(QueryDispatch);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM