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
Достоинства
- 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