npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

direct-react-router

v2.0.0

Published

[![NPM version][npm-image]][npm-url] [![Bundle size][bundlephobia-image]][bundlephobia-url] [![Build status][travis-image]][travis-url] [![License][license-image]][license-url]

Downloads

22

Readme

direct-react-router

NPM version Bundle size Build status License

Достоинства

  • redux first → не зависит от жизненного цикла компонентов → нет сайд-эффектов в компонентах (например, больше не нужна генерация действий в componentDidMount)
  • настройки роутинга в одном месте → в конфиге плоский список роутов и алиасы для них
  • алиасы вместо url → роутер парсит алиасы роутов в адресах и генерирует по алиасам правильные url → не нужно завязываться в коде на конкретные url (в т.ч. не нужны спец. компоненты для условного рендеринга)
  • можно использовать по частям (например, только middleware) → расширяемость (например, можно использовать с react-router, а можно и не использовать 😋)
  • поддержка TypeScript из коробки

Как установить

npm i direct-react-router

Зависимости: react ^16.8.6, redux ^4.0.1, react-redux ^7.0.0, history ^5.0.0.

Как использовать

Конфигурация

Конфигурация задает плоский список роутов и алиасы для них. Также вам понадобится экземпляр history.

import { createBrowserHistory } from 'history';
import { RouterConfig } from 'direct-react-router';

const history = createBrowserHistory();

const config: RouterConfig = {
    routes: {
        PAGE1: '/p1',
        PAGE2: '/p2/:login/count/:num'
    }
};

Синтакис шаблонов путей:

const config: RouterConfig = {
    routes: {
        EXAMPLE1: '/:foo/:bar',  // named parameters
        EXAMPLE2: '/:foo/:bar?', // optional parameters
        EXAMPLE3: '/:foo*',      // zero or more
        EXAMPLE4: '/:foo+',      // one or more

        // see details: https://npmjs.org/package/path-to-regexp
    }
};

При сравнении всегда exact === true, поэтому порядок описания роутов не важен. Если текущему URL соответствует несколько роутов, будет исключение.

Middleware

import { createRoutingMiddleware } from 'direct-react-router';
// ...
const routerMiddleware = createRoutingMiddleware(config, history);
// ...
const store = createStore(rootReducer, routerMiddleware);

Теперь при каждом изменении url будет генериироваться action, который вы можете обрабатывать любым нужным способом. В него приходит информация о новом URL и его параметрах + его alias в конфиге.

/*
{
    type: '@@direct-react-router/LOCATION_CHANGED',
    location: {
        key: '<route key>',
        pathname: '...',
        search: '...',
        hash: '...',
        params: { ... },
        query: { ... }
    },
    action: 'PUSH'
}
*/

Reducer + state

Вы можете подключить готовый редюсер, который будет обрабатывать события изменения URL и класть информацию в state. Также он отвечает за начальное состояние (начальный url).

import { RouterLocation, createRoutingReducer } from 'direct-react-router';

export interface State {
    location: RouterLocation;
    // ...
}

const rootReducer = combineReducers({
    location: createRoutingReducer(
        config,  // конфиг роутера
        history.location // начальный url
    ),
    // ...
});

Ссылки

import { Link } from 'direct-react-router';
// ...

render() {
    const href = '/p2/test/count/12?aa=1&bb=2#xxx';
    return <Link href={href}>page1</Link>;
}

/*
location: {
    pathname: '/p2/test/count/12',
    search: '?aa=1&bb=2',
    hash: '#xxx',
    key: 'PAGE2',
    params: { login: 'test', num: '12' },
    query: { aa: '1', bb: '2' }
}
*/

Генерация ссылок по ключам

import { AdvancedLink, RouterContext } from 'direct-react-router';
// ...

render() {
    return (
        <Provider store={store}>
            <RouterContext.Provider value={{ config }}>
                ...
                <AdvancedLink
                    routeKey='PAGE2'
                    params={{ login: 'test', num: '12' }}
                    query={{ aa: '1', bb: '2' }}
                    hash='#xxx'
                >
                    page2
                </AdvancedLink>
                ...
            </RouterContext.Provider>
        </Provider>
    );
}

/*
href:
    /p2/test/count/12?aa=1&bb=2#xxx
location: {
    pathname: '/p2/test/count/12',
    search: '?aa=1&bb=2',
    hash: '#xxx',
    key: 'PAGE2',
    params: { login: 'test', num: '12' },
    query: { aa: '1', bb: '2' }
}
*/

Внимание! проверьте, что нет лишних перерисовок

History options

Через пропсы компонентов Link и AdvancedLink можно настраивать параметры обращения к history api:

  • replace?: boolean - использовать REPLACE (по умолчанию PUSH)
  • state?: object | null - объект состояния, ассоциированный с новой записью истории браузера
  • forceReload?: boolean - перезагружать страницу при переходе по ссылке

Base path

Везде работаем с относительными путями.

  • Для адресной строки — указать basename в createBrowserHistory.
  • Для генерации ссылок — пробросить basename через контекст.
import { Link, RouterContext } from 'direct-react-router';
// ...
const basename = 'your/base/path';

// учитываем basename при обработке url
const history = createBrowserHistory({ basename });


render() {
    return (
        // учитываем basename при генерации url для ссылок
        <RouterContext.Provider value={{ basename }}>
            ...
            <Link href='/test/xxx' />
            ...
        </RouterContext.Provider>
    );
}

/*
href:
    /your/base/path/test/xxx
location: {
    pathname: '/test/xxx',
    ...
}
*/

Генерировать action при открытии страницы

Middleware генерирует экшены при изменении url в адресной строке. При открытии страницы экшен с текущим url по умолчанию не генерируется. Если он вам нужен, сгенерируйте его руками.

import { parseLocation, changeLocation } from 'direct-react-router';
// ...

const routerLocation: RouterLocation = parseLocation(config, history.location);
store.dispatch(changeLocation(routerLocation));

todo

  • [x] импорт компонента ссылки из корня
  • [x] устанавливать начальный path
  • [x] location по умолчанию
  • [x] редюсер
  • [x] генерация ссылок по ключу????? (~~откуда брать конфиг? как вариант, можно коннектить каждую ссылку к стору и складывать конфиг в стор~~ конфиг передается через контекст)
  • [x] обрубать ? в query string
  • [x] приоритет роутов - задаем в виде массива
  • [x] придумать, как задавать query string и hash для AdvancedLink
  • [x] exact
  • [x] base path
  • [x] атрибуты ссылки
  • [x] callHistoryMethod, который принимает RouteArgs + добавить параметр с названием методов
  • [x] выключать spa переходы через пропсы
  • [ ] persistQuery
  • [ ] переделать базовый компонент на HOC
  • [ ] query-string options

подумать

  • [x] проверить, как ведет себя звездочка в роутах
  • [ ] проверить, что приходит в action, если адрес - url encoded
  • [ ] подумать, нужно ли кодировать hash при генерации url
  • [ ] когда происходит отписка от событий history

License

MIT