No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Reto: página de búsquedas con navegación

26/30
Recursos

Aportes 11

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

Este reto es muy fácil con useSearchParams!! Qué lástima que no lo descubrí antes

import React from 'react'
import { useSearchParams } from 'react-router-dom'

export function TodoSearch({ setSearchValue, loading }) {
    const [searchParams, setSearchParams] = useSearchParams()
    const paramsValue = searchParams.get('search')

    const onSearchValueChange = ({ target: { value } }) => {
        setSearchValue(value)
        setSearchParams({ search: value })
    }

    return (
        <input
            className={`TodoSearch ${loading && 'TodoSearch--loading'}`}
            onChange={onSearchValueChange}
            value={paramsValue ?? ''}
            placeholder="Search a To-Do"
        />
    )
}

Uff, cuando te enfrentas a retos como este te es cuando realmente comprendes lo que creías entender de la clase.
Logré de resolverlo de la siguiente manera:

  • Dentro de App.js modifiqué la propiedad path para que aceptara el valor searchValue, también dejé el valor anterior para que la Route de HomePage siguiera funcionando aunque no se enviara el valor searchValue:
  • En TodoSearch.js utilicé useParams para cachar el valor searchValue de la url y se lo envie como value al input

    -Dentro de un useEffect() evalúo si params.searchValue existe, sí es así, actualizo el searchValue que recibimos desde props.
  • En la función onSearchValueChange agregue un navigate hacia el valor del input:

    No sé si es la mejor solución, pero funciona 😃

Para resolver el reto se puede ulitlizar el hook useSearchParams



En el HomePage.jsx agregamos:

 const [params, setParams] = useSearchParams();

Y se lo enviamos a TodoSearch:

<TodoSearch
          searchValue={searchValue}
          setSearchValue={setSearchValue}
          params={params}
          setParams={setParams}
        />

Ya en TodoSearch.jsx lo manejamos de la siguiente manera:

import React, { useEffect } from "react";

function TodoSearch({ searchValue, setSearchValue, params, setParams }) {
  const onSearchValueChange = (event) => {
    setSearchValue(event.target.value);

    let params = {
      search: event.target.value,
    };
    setParams(params);
  };

  useEffect(() => {
    const search = params.get("search") ?? "";
    setSearchValue(search);
  }, [params]);

  return (
    <input
      className="todo-search"
      placeholder="Search..."
      type="text"
      value={searchValue}
      onChange={onSearchValueChange}
    />
  );
}

export { TodoSearch };

De esa manera logramos el siguiente resultado

A caray!!

Mi solucion consiste en:

  1. Crear un ruta hija dinamica.
<Route path='/' element={<HomePage/>}>
    <Route path=':slug' element={<HomePage/>}/>
</Route>

Quedando asi App.js:

function App() {
  
  return (
    <HashRouter>
      <Routes>
        <Route path='/' element={<HomePage/>}>
          <Route path=':slug' element={<HomePage/>}/>
        </Route>
        <Route path='/new' element={<NewTodoPage/>}/>
        <Route path='/edit/:id' element={<EditTodoPage/>}/>
        <Route path='*' element={<p>No Found!</p>}/>
      </Routes>
    </HashRouter>
  );
}

export { App };
  1. Con el ayuda de useNavigate, creo la ruta con cada ingreso de teclado y navego a ella.
const onSearchValueChange = (event) => {
    setSearchValue(event.target.value);
    navigate('?search=' + event.target.value);
};
  1. Sí el usuario ingresa una url directa con su busqueda, me ayudo de una valorInput global y valido si hay una busqueda con ayuda de useLocation, espero a la carga del primer render y en 100ms realizo la busqueda.
let textSearchValue = searchValue;

if(location.search && !loading) {
    textSearchValue = location.search.replace('?search=', '');
    setTimeout(()=>setSearchValue(textSearchValue),50);
}

Quedando finalmente asi el archivo index.js de TodoSearch como sigue:

function TodoSearch({ searchValue, setSearchValue, loading }) {
  
  const navigate = useNavigate();
  const location = useLocation();
  let textSearchValue = searchValue;

  const onSearchValueChange = (event) => {
    setSearchValue(event.target.value);
    navigate('?search=' + event.target.value);
  };

  if(location.search && !loading) {
    textSearchValue = location.search.replace('?search=', '');
    setTimeout(()=>setSearchValue(textSearchValue),50);
  }

  return (
    <input
      className="TodoSearch"
      placeholder="Cebolla"
      value={textSearchValue}
      onChange={onSearchValueChange}
      disabled={loading}
    />
  );
}

export { TodoSearch };

yo utilice el hook useSearchParams para poder modificar los query params en la url, y también useEffect con un array vacio en el segundo argumento para que solo en el primer render se asigne el valor del searchParams al input

No quize aplicar eso en el TodoMachine pero lo implemente aqui
https://briandacampoy.github.io/poke-api/#/

Para resolver el reto tuve que hacer:

  1. Crear un effect para que escuhe cambios en searchValue y navegar al mismo location con un param search
  let location = useLocation();
  let navigate = useNavigate();
  React.useEffect(() => {
    if (searchValue.length > 0) {
      navigate({
        pathname: location.pathname,
        search: `?search=${searchValue}`,
      })
    }
  }, [searchValue])
  1. utilizo el hook useSearchParams de react-router-dom para traer ese valor cuando cambie la ruta
let [searchParams, setSearchParams] = useSearchParams();

const wordFromPath = searchParams.getAll('search')[0];
  1. verifico que el parametro search traiga algun valor y si esa asi hago la busqueda por ese valor y actualizo el valor de searchValue
if (!searchValue.length >= 1) { 

    if(wordFromPath) {
      searchedTodos = todos.filter(todo => {
        const todoText = todo.text.toLowerCase();
        const searchText = wordFromPath.toLowerCase();
        return todoText.includes(searchText);
      });
      setSearchValue(wordFromPath)
    }
    else {
      searchedTodos = todos;
    }

  }

la verdad no se si sea la opcion mas optima ya que por cada cambio de searchValue estoy navegando a la misma pagina, quisiera saber cual seria una mejor opcion

https://nieto35.github.io/personal-page/#/api

Reto completado con Api de git Hub

Se utilizaría la propiedad search del hook useLocation para capturar la query que se le pasa a la url. Teniendo eso se hace el filtrado y se muestra el valor en el input. Y para el otro caso, se utilizaría el useNavigate al hacer submit.

Me suena q es con useLocation 🤔