【问题标题】:React: Data not showing until I search反应:直到我搜索数据才显示
【发布时间】:2021-03-20 07:47:15
【问题描述】:

我有一个用于在表格中搜索名称的反应组件。 一切正常,除了我必须先搜索才能看到数据。如果我在没有搜索的情况下登陆页面,我将没有信息。

如何先显示数据,然后在其中搜索?我将 React 和 Laravel 用于 API。

我的 JS 代码:

import React, { Component } from "react";
import Widget1 from "../components/Widget1";
import Header from "../components/Header";
import axios from "axios";
import { Link } from "react-router-dom";
import Echo from "laravel-echo";
import { Container, Dropdown, ListGroup, Button } from "react-bootstrap";
import ReactDOM from "react-dom";

import { Table, Thead, Tbody, Tr, Th, Td } from "react-super-responsive-table";
import "react-super-responsive-table/dist/SuperResponsiveTableStyle.css";
import { useState } from "react";

function SearchPatient() {
  const [data, setData] = useState([]);

  async function search(key) {
    console.warn(key);
    let result = await fetch("http://localhost:8000/api/search/" + key);
    result = await result.json();
    console.warn(result);
    setData(result);
  }

  return (
    <div>
      <Container>
        <div className="form-group">
          <label htmlFor="exampleInputEmail1">Search</label>
          <input
            type="text"
            className="form-control"
            placeholder="Search"
            id="nom"
            onChange={(e) => search(e.target.value)}
          />
        </div>

        <Table className="table table-hover">
          <Thead className="thead-light text-center">
            <Tr>
              <Th>N°</Th>
              <Th style={{ width: "6%" }}>NOM</Th>
              <Th>PRÉNOM</Th>
            </Tr>
          </Thead>
          <Tbody className="text-center">
            {data.map((patient) => (
              <Tr>
                <Td style={{ verticalAlign: "middle" }} className="text-muted">
                  <b>{patient.id}</b>
                </Td>
                <Td style={{ verticalAlign: "middle" }}>{patient.nom} </Td>
                <Td style={{ verticalAlign: "middle" }}>{patient.prenom} </Td>
              </Tr>
            ))}
          </Tbody>
        </Table>
      </Container>
    </div>
  );
}

export default SearchPatient;

if (document.getElementById("SearchPatient")) {
  ReactDOM.render(<SearchPatient />, document.getElementById("SearchPatient"));
}

API:

Route::get('/search/{key}/', [PatientController::class, 'search']);

Laravel 控制器:

public function search($key)
{
    return Patient::where('nom','Like',"%$key%")->get();
}

【问题讨论】:

    标签: javascript reactjs laravel


    【解决方案1】:

    您需要加载数据来显示它,而您并没有这样做。您需要在组件渲染上运行副作用以获取初始数据。如果您使用空 key 进行搜索会产生所有数据,那么您需要对所有内容使用单一效果,如果以其他方式加载初始数据,则需要两种效果。

    空搜索返回所有数据:

    // We store current search value here and changing this state variable will rerun side effect
    const [search, setSearch] = useState("");
    
    async function getSearchResult(key, signal) {
      let result = await fetch("http://localhost:8000/api/search/" + key, {
        signal,
      });
      result = await result.json();
      setData(result);
    }
    
    // Effect will fire on first render and whenever `search` variable changes
    useEffect(
      function () {
        // We need AbortController to prevent race condition when user is sending one request after another
        // Since you are firing this on every keystroke, it is advisable to either debounce, or throttle your search
        let controller = new AbortController();
        let signal = controller.signal;
        getSearchResult(search, signal).catch((error) => {
          // Handling errors, especially with promises is very important
          console.error(error);
        });
        return () => controller.abort();
      },
      [search]
    );
    
    <div className="form-group">
      <label htmlFor="exampleInputEmail1">Search</label>
      <input
        type="text"
        className="form-control"
        placeholder="Search"
        id="nom"
        onChange={(event) => setSearch(event.target.value)}
      />
    </div>;
    
    

    对初始数据的不同请求:

    // We store current search value here and changing this state variable will rerun side effect
    const [search, setSearch] = useState("");
    
    async function getSearchResult(key, signal) {
      let result = await fetch("http://localhost:8000/api/search/" + key, {
        signal,
      });
      result = await result.json();
      setData(result);
    }
    
    // Effect will fire on first render and whenever `search` variable changes
    useEffect(
      function () {
        // We will opt out if search is not empty
        if (search !== "") return;
        let controller = new AbortController();
        let signal = controller.signal;
        fetch("http://localhost:8000/api/intial_data", {
          signal,
        })
          .then((result) => result.json())
          .then((result) => setData(result))
          .catch((error) => console.error(error));
        return () => controller.abort();
      },
      [search]
    );
    
    // Effect will fire on first render and whenever `search` variable changes
    useEffect(
      function () {
        // We will opt out if search is empty
        if (search === "") return;
        // We need AbortController to prevent race condition when user is sending one request after another
        // Since you are firing this on every keystroke, it is advisable to either debounce, or throttle your search
        let controller = new AbortController();
        let signal = controller.signal;
        getSearchResult(search, signal).catch((error) => {
          // Handling errors, especially with promises is very important
          console.error(error);
        });
        return () => controller.abort();
      },
      [search]
    );
    
    <div className="form-group">
      <label htmlFor="exampleInputEmail1">Search</label>
      <input
        type="text"
        className="form-control"
        placeholder="Search"
        id="nom"
        onChange={(event) => setSearch(event.target.value)}
      />
    </div>
    

    注意AbortController。重要的是,每个后续请求都将取消之前的请求,因为如果之前的请求将在下一个请求之后完成,您最终可能会得到错误的数据。

    【讨论】:

    • 非常感谢您的详细解释。仍然是反应的初学者,并且已经设法理解了这个问题。现在,当我尝试显示数据时出现以下错误search.map is not a function,我在代码中替换了搜索而不是耐心。
    • 我猜是因为 useState 不是数组?
    • 什么是搜索,为什么要映射它?在我的示例中,search 是一个字符串
    • 为了在表格中显示数据。在您提供的示例中,我不知道您如何显示检索到的数据。就我而言,我在数组上使用它。
    • 但是你为什么要迭代 search 而不是 data?效果之外的所有代码、新状态变量 searchinput 上的事件处理程序保持不变。
    【解决方案2】:

    您需要在useEffect 挂钩中获取数据。您可以阅读有关 useEffect 的更多信息,但简而言之,您可以在组件挂载时使用它做一些事情

    您可以在 useState 挂钩之后添加此 useEffect 行:

    useEffect(() => {
      let result = await fetch(/* Your get request */);
      result = await result.json();
      setData(result)
    }, [])
    

    空数组表示您想在组件挂载时运行一次。我强烈建议阅读更多关于useEffect 和依赖数组的信息

    【讨论】:

      【解决方案3】:

      您遇到这种情况是因为您设置的默认状态是一个空数组。

      当你做出这个定义时你就这样做了

       const [data,setData]=useState([]);
      

      因此,要使用useEffect 挂钩来调用端点以返回要查看的默认数据,从而获得一些默认数据。您还可以将其视为一种由于状态更改而触发副作用的机制。

      请参阅下面的 sn-p,了解您的代码应该是什么样子。

      // 
      useEffect(() => {
          //Initial API call with default results
          //Set data with API results
      }, [data]); 
      //data controls when the component updates, so when you call you call the search function, it'll cause a change to the data value and trigger the `useEffect` hook.
      

      通过video了解更多信息

      【讨论】:

      • 这将不断触发,因为它会更改数据、渲染、请求新数据、设置新数据等等
      猜你喜欢
      • 2019-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多