Saya memiliki halaman pencarian, dan ketika pengguna mencari sesuatu, misalnya, kursi, itu akan mendorong ke rute /search-page/chairs menggunakan router.push("/search-page/" + searchQuery);

Namun, masalah yang muncul adalah ketika pengguna melakukan pencarian lain saat berada di dalam halaman pencarian, kueri di URL, di bilah alamat, diperbarui, tetapi halaman tidak menyegarkan, sehingga tidak memperbarui produk. Saya telah mencoba router.push("/search-page/" + searchQuery, undefined, {shallow: false}); untuk mencoba memaksa router.push agar tidak dangkal, tetapi itu tidak berhasil. Saya juga sudah mencoba

componentDidUpdate(prevProps){
  if(this.state.router.asPath != prevProps.router.asPath){
   updateProducts()
 }
}

Untuk memeriksa apakah saat komponen diperbarui, bahwa URL sebelumnya tidak sama dengan URL saat ini. Namun, pernyataan if ini sepertinya tidak berfungsi juga. Ada yang tidak diperbarui dengan benar. Karena saya menggunakan NextJS, mungkin ada sesuatu yang bisa saya lakukan mengenai getServerSideProps? Tapi saya tidak terlalu terbiasa dengan cara kerja getServerSideProps atau getIntialProps. Atau mungkin ada cara untuk memperbarui kueri di URL, dan kemudian memaksa menyegarkan halaman setelahnya, seperti fungsi panggilan balik. Terima kasih

0
matt1331 12 Mei 2021, 05:05

2 jawaban

Jawaban Terbaik

Salah satu pendekatan yang saya gunakan adalah membungkus search query JSX yang dikembalikan dalam sebuah memo, atau memo untuk memperbarui status saat perubahan. Ini kode dari proyek pencarian subreddit yang saya buat beberapa bulan lalu di samping

import { FC, useEffect, useMemo, useState } from 'react';
import cn from 'classnames';
import css from './Searchbar.module.css';
import { useRouter } from 'next/router';
import { Input } from '../UI';
import { filterQuery } from '@/lib/helpers';

interface Props {
    className?: string;
    id?: string;
}

const Searchbar: FC<Props> = ({ className, id = 'r/' }) => {
    const router = useRouter();
    const [value, setValue] = useState('');
    useEffect(() => {
        // router.prefetch(url, as)
        router.prefetch('/r/[display_name]', `/r/${router.query}`, {
            priority: true
        });
    }, [value]);

    return useMemo(
        () => (
            <div
                className={cn(
                    'relative bg-accents-1 text-base w-full transition-colors duration-150',
                    className
                )}
            >
                <label className='sr-only' htmlFor={id}>
                    /r/ - search by subreddit name
                </label>
                <div className='absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none'>
                    <span className='text-gray-100 font-semibold sm:text-base'>
                        /r/
                    </span>
                </div>
                <Input
                    id={id}
                    name={id}
                    onChange={setValue}
                    className={css.input}
                    defaultValue={
                        router && router.query ? (router.query.q as string) : ''
                    }
                    onKeyUp={e => {
                        e.preventDefault();

                        if (e.key === 'Enter') {
                            const q = e.currentTarget.value;

                            router.push(
                                {
                                    pathname: `/r/${q}`,
                                    query: q ? filterQuery({ q }) : {}
                                },
                                undefined,
                                { shallow: true }
                            );
                        }
                    }}
                />
                <div className={css.iconContainer}>
                    <svg
                        className={css.icon}
                        fill='rgb(229, 231, 235)'
                        viewBox='0 0 20 20'
                    >
                        <path
                            fillRule='evenodd'
                            clipRule='evenodd'
                            d='M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z'
                        />
                    </svg>
                </div>
            </div>
        ),
        []
    );
};

export default Searchbar;
@/components/Searchbar.module.css
.input {
    @apply bg-redditSearch px-3 pl-7 py-2 appearance-none w-full transition duration-150 ease-in-out pr-10 text-gray-100 font-semibold;

    @screen sm {
        min-width: 300px;
        @apply text-lg;
    }
    @screen md {
        min-width: 600px;
        @apply text-lg;
    }
}

.input:focus {
    @apply outline-none text-gray-100;
}

.iconContainer {
    @apply absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none;
}

.icon {
    @apply h-5 w-5;
}

Saya mengambil lebih dulu kemenangan yang ditargetkan di dalam kait useEffect untuk meningkatkan UX di lingkungan produksi; itu akan meningkatkan UX dalam pengembangan juga tetapi prefetching hanya berfungsi di prod saat ini.

Kemudian, ada rute @/pages/api yang menangani nilai input pengguna sebagai berikut:

@/pages/api/snoosearch.ts
import { Subreddit, Listing } from 'snoowrap';
import { NextApiRequest, NextApiResponse } from 'next';
import { r } from '@/lib/snoo-config';

export type SearchSubreddits = {
    subreddit: Listing<Subreddit> | never[];
    found: boolean;
};

export default async function (
    req: NextApiRequest,
    res: NextApiResponse<SearchSubreddits>
) {
    const { q } = req.query;
    console.log(q);
    const data = q
        ? await r.searchSubreddits({
                query: (q as string) ?? 'snowboarding',
                count: 10,
                limit: 3
          })
        : [];
    res.statusCode = 200;
    res.setHeader(
        'Cache-Control',
        'public, s-maxage=1200, stale-while-revalidate=600'
    );

    return res.status(200).json({
        subreddit: data,
        found: true
    });
};

Jadi, lambda ini menyuntikkan getStaticPaths dari subdirektori dinamis untuk menangani pembuatan jalur statis waktu nyata (serta lokalisasi opsional jika menggunakan perutean internasional) dan mengisi konten dari setiap subreddit yang diberikan melalui ISR.

Jika Anda harus menulis tes di Nextjs menggunakan Jest di lingkungan TypeScript, Anda mungkin terbiasa untuk mengejek router berikutnya dengan mereplikasinya di lingkungan pengujian Anda. Ini membantu saya belajar banyak tentang internal router:

TLDR - Memoisasi bilah pencarian tempat pencarian pengguna dikirimkan, status pembaruan yang memaksa render non-dangkal yang seharusnya menyelesaikan masalah Anda

// Mocks useRouter
type PrefetchOptions = {
    priority?: boolean;
    locale?: string | false;
};

const useRouter = jest.spyOn(
    require('next/router'),
    'useRouter'
);

/**
 * mockNextUseRouter
 * Mocks the useRouter React hook from Next.js on a test-case by test-case basis
 */
export function mockNextUseRouter(props: {
    route: string;
    prefetch(
        url: string,
        asPath?: string,
        options?: PrefetchOptions
    ): Promise<void>;
    pathname: string;
    query: string;
    asPath: string;
}) {
    useRouter.mockImplementationOnce(() => ({
        route: props.route,
        prefetch: props.prefetch,
        pathname: props.pathname,
        query: props.query,
        asPath: props.asPath
    }));
}
0
Andrew Ross 12 Mei 2021, 03:50

Memetikan ada yang bertanya-tanya, saya berhasil mengetahuinya dengan menggunakan window.location

componentDidUpdate() {

  var str = window.location.pathname;
  var n = str.lastIndexOf('/');
  var result = str.substring(n + 1);
  if(result != this.state.searchQuery){//if the current URL doesn't match the URL stored in the state (which is the previous url before making a new search)
    //grab the query from the current URL, and update the searchQuery state with that query from the current URL
    this.updateProducts(result);
  }
}

Dalam kode berikut, ketika componentUpdates, ia mengambil parameter kueri dari window.location.pathname menggunakan substring. Kemudian ia membandingkan param kueri dari window.location dengan param kueri dari this.state.searchQuery, jika mereka tidak sama, maka perbarui this.state.searchQuery dengan param yang diekstrak dari window.location.pathname, dan panggil berfungsi untuk memperbarui produk berdasarkan input pengguna.

1
matt1331 12 Mei 2021, 03:24