【问题标题】:Pass data between two independent components in ReactJS在 ReactJS 中的两个独立组件之间传递数据
【发布时间】:2020-10-16 11:27:43
【问题描述】:

我正在使用 ReactJS 构建一个 Web 应用程序,这需要我实现一个搜索。到目前为止,已经使用带有输入元素的表单实现了搜索(我为此使用了Fuse.js 库)。该表单在 NavBar 中实现,在用户键入搜索查询后,他将被重定向到“localhost:3000/search”URL,在那里他可以看到与他的查询相对应的结果。

这是我在 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;

我需要在另一个 SearchPage 中显示相应的结果,它会在提交后从该组件中获取查询,然后显示结果。这是我为它编写的代码。

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;

仅供参考,useSpaces() 是一个函数,它可以提供所有数据(它正确地提供),filteredspaces 是我希望在屏幕上显示的最终结果数组。所有这些事情都完美无缺。

不过,我不知道如何在两个组件之间传递查询。我在SearchPage(queries) 中使用的queries 是一个虚拟变量。我是 React 的新手,并且我已经了解了 Redux,但是在 2 个组件之间简单地传递一个值似乎需要做很多工作(我可能错了)。正如您可以清楚地观察到的,这些组件不是相关的而是独立的。有没有一种简单的方法可以做到这一点?任何帮助将不胜感激!

【问题讨论】:

    标签: javascript reactjs components


    【解决方案1】:

    您可以使用useContenxtuseReducer 挂钩以获得更简单的状态结构。我创建了一个小例子here。你可以在docs找到更多参考

    基本上从您的应用程序开始,您将首先创建一个上下文并将调度和查询作为值传递给您的 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>
      );
    }
    

    queryReducer 可能是这样的:

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

    以及您可以从您的提供者处使用的任何组件:

    在您的搜索栏

    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} />
    

    在您的搜索页面

    import React, { useContext } from "react";
    import { QueryDispatch } from "./App";
    
    const SearchPage = () => {
      const { query } = useContext(QueryDispatch);
    

    【讨论】:

    • 感谢这种方法。但是,我在我的代码中使用打字稿,它在 app.tsx 文件中显示如下语法错误:Type '{ dispatch: React.Dispatch&lt;any&gt;; queries: any; }' is not assignable to type 'string'. 你能帮我吗?据我了解,这是因为我们将初始状态分配为const QueryDispatch = React.createContext("");
    • 好的,我明白了。从网上的几个答案中,我意识到这是一个打字稿问题,我通过定义一个与所需数据类型对应的接口来解决它。
    • 是的!现在一切正常。两个组件之间正在发送数据。我还有一个问题。刷新页面时,查询的值会被清除吗?是否可以存储它,这样即使页面刷新,我们也可以知道它在那里!
    • 对于刷新时的数据持久性,您可以使用localStoragesessionStorage。主要是你的初始状态,你会选择const initialState = JSON.parse(localStorage.getItem('query')) || { query: "" }。并且在某些时候,您会在 localStorage 上保持 redux 状态,例如 localStorage.setItem('query', JSON.stringify({ query }))。在您的情况下,您可能有兴趣仅在表单提交上坚持。您可能有兴趣更频繁地设置 localState 的其他位置。只记得在设置之前进行字符串化,在检索之前进行解析。
    • 知道了。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    相关资源
    最近更新 更多