English | [简体中文](./README.zh-cn.md)
npm install @alist/reactEnglish | 简体中文
> @alist/react is based on react and @alist/core is already built in. It provide API to manuplate list state and components for rendering support.
> it mainly includes:
>
> -
> -
> -
> -
> -
> -
> -
> -
``bash`
npm install --save @alist/react
- Usage
- Quick Start(URL Mode)
- DataSource Mode
- Multiple Mode
- Request Format
- Customize Request
- Effects
- Components
-
-
-
-
-
-
-
- Hook
- useList
- useTable
- useConsumer
- useFilter
- useFilterItem
- usePagination
- useMultipleProvider
- API
- createListActions
- createAsyncListActions
- ListEffectHooks
- createListEffectHook
- Interfaces
- IListMode
- IList
- IListActions
- IListAsyncActions
- IListUIProps
- ITableProps
- ITableHook
- IFilterHook
- IFilterItemHook
- IPaginationHook
- IMultipleHook
---
#### Quick Start(URL Mode)
Pass url and it set to URL Mode and automatically request. Check Request Format for more information.
`jsx
import React, { useState, useEffect, useRef } from 'react'
import {
ListProvider, TableProvider, PaginationProvider, MultipleProvider,
createListActions,
ListLifeCycleTypes,
ListEffectHooks,
createListEffectHook
} from '@alist/react'
const Input = (props) => {
const [value, setValue] = useState(props.value)
useEffect(() => {
if (props.value !== value) {
setValue(props.value)
}
}, [props.value])
return {
setValue(e.target.value)
props.onChange(e.target.value)
}} />
}
const Pagination = () => {
const [currentPage, setCurrentPage] = useState(1)
return
{(props) => }
currentPage:{props.currentPage} ,
pageSize:{props.pageSize} ,
total:{props.total} ,
totalPages:{props.totalPages}
}
const App = () => {
const actions = createListActions()
const url = 'https://mocks.alibaba-inc.com/mock/alist/data'
return
{(props) => {
if (props.loading) return loading...
return props.dataSource.map((item, index) => {item.label}, {item.name})
}}
ReactDOM.render(
`
#### DataSource Mode
Pass dataSource will set to DataSource Mode which will automatically paginate.
`jsx
import React, { useState, useEffect, useRef } from 'react'
import {
ListProvider, TableProvider, PaginationProvider, MultipleProvider,
createListActions,
ListLifeCycleTypes,
ListEffectHooks,
createListEffectHook
} from '@alist/react'
const Input = (props) => {
const [value, setValue] = useState(props.value)
useEffect(() => {
if (props.value !== value) {
setValue(props.value)
}
}, [props.value])
return {
setValue(e.target.value)
props.onChange(e.target.value)
}} />
}
const Pagination = () => {
const [currentPage, setCurrentPage] = useState(1)
return
{(props) => }
currentPage:{props.currentPage} ,
pageSize:{props.pageSize} ,
total:{props.total} ,
totalPages:{props.totalPages}
}
const getDataSource = (len) => {
const dataSource = []
for ( let i = 0; i < len; i++ ) {
dataSource.push({ label: id: #${Math.random().toString(36).slice(-8)}, value: i })
}
return dataSource
}
const App = () => {
const actions = createListActions()
const dataSource = getDataSource(20)
const cutsomHook$ = createListEffectHook('diy')
return
ReactDOM.render(
`
#### Multiple Mode
Use MultipleProvider and setMultipleData to split one response data into multiple pieces for consumption
`jsx
import React, { useState, useEffect, useRef } from 'react'
import {
ListProvider, TableProvider, PaginationProvider, MultipleProvider,
createListActions,
ListLifeCycleTypes,
ListEffectHooks,
createListEffectHook
} from '@alist/react'
const Input = (props) => {
const [value, setValue] = useState(props.value)
useEffect(() => {
if (props.value !== value) {
setValue(props.value)
}
}, [props.value])
return {
setValue(e.target.value)
props.onChange(e.target.value)
}} />
}
const Pagination = () => {
const [currentPage, setCurrentPage] = useState(1)
return
{(props) => }
currentPage:{props.currentPage} ,
pageSize:{props.pageSize} ,
total:{props.total} ,
totalPages:{props.totalPages}
}
const getDataSource = (len) => {
const dataSource = []
for ( let i = 0; i < len; i++ ) {
dataSource.push({ label: id: #${Math.random().toString(36).slice(-8)}, value: i })
}
return dataSource
}
const App = () => {
const actions = createListActions()
useEffect(() => {
actions.setMultipleData({
a1: getDataSource(15),
a2: getDataSource(15),
})
}, [])
return
ReactDOM.render(
`
#### Request Format
As shown in the figure, the request process can be regarded as a black box, and the request parameters are IListQueryData, user can influence the process in the following three ways:
* formatBefore: Modify the data before the request
* formatAfter: Modify the data returned by the request
* query: Directly proxy the entire request process
Just make sure that the final result is IListResponse. AList will do the rest for you。
#### Customize Request
By Passing the query props and you can completely customize the way of request
`jsx
import React, { useState, useEffect, useRef } from 'react'
import {
ListProvider, TableProvider, PaginationProvider, MultipleProvider,
createListActions,
ListLifeCycleTypes,
ListEffectHooks,
createListEffectHook
} from '@alist/react'
const Input = (props) => {
const [value, setValue] = useState(props.value)
useEffect(() => {
if (props.value !== value) {
setValue(props.value)
}
}, [props.value])
return {
setValue(e.target.value)
props.onChange(e.target.value)
}} />
}
const Pagination = () => {
const [currentPage, setCurrentPage] = useState(1)
return
{(props) => }
currentPage:{props.currentPage} ,
pageSize:{props.pageSize} ,
total:{props.total} ,
totalPages:{props.totalPages}
}
const getDataSource = (len) => {
const dataSource = []
for ( let i = 0; i < len; i++ ) {
dataSource.push({ label: id: #${Math.random().toString(36).slice(-8)}, value: i })
}
return dataSource
}
const App = () => {
const actions = createListActions()
const query = async ({ url, method, data }) => {
const { currentPage, pageSize } = data
return fetch(${url}?_t=${new Date().getTime()}&sort=%7B%7D&pageSize=${pageSize}¤tPage=${currentPage}&filterData=%7B%7D,
{
"credentials":"include",
"headers": {
"accept":"application/json, text/plain, /",
"accept-language":"en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6",
"content-type":"application/x-www-form-urlencoded charset=UTF-8",
"sec-fetch-mode":"cors",
"sec-fetch-site":"cross-site"
},
"referrer": location.href,
"referrerPolicy":"no-referrer-when-downgrade",
"body":null,
"method":"GET",
"mode":"cors"
}).then((resp) => {
return resp.json()
}).then(resp => {
const { code, data: respData, message } = resp
if ([ 0, 200, '0', '200' ].indexOf(code) === -1) {
throw new Error(message || 'System Error')
} else {
const total = 6
const totalPages = Math.ceil(total / pageSize)
let dataList
if (currentPage > totalPages) {
dataList = []
} else if (currentPage === totalPages) {
dataList = getDataSource(total % pageSize)
} else {
dataList = getDataSource(pageSize)
}
return {
dataListProvider,
currentPage,
pageSize,
total,
totalPages,
}
return respData
}
});
}
const url = 'https://mocks.alibaba-inc.com/mock/alist/data'
return
ReactDOM.render(
`
#### Effects
Consumption life cycle hook of list vie effects. Check ListLifeCycleTypes for more infomation.
`jsx
import React, { useState, useEffect, useRef } from 'react'
import {
ListProvider, TableProvider, PaginationProvider, MultipleProvider,
createListActions,
ListLifeCycleTypes,
ListEffectHooks,
createListEffectHook
} from '@alist/react'
const App = () => {
const actions = createListActions()
const url = 'https://mocks.alibaba-inc.com/mock/alist/data'
return
$(ListLifeCycleTypes.ON_LIST_WILL_INIT).subscribe(() => {
console.log('list will init')
})
$(ListLifeCycleTypes.ON_LIST_INIT).subscribe(() => {
console.log('list init')
})
$(ListLifeCycleTypes.ON_LIST_BEFORE_QUERY).subscribe((queryData) => {
console.log('list before query', queryData)
})
$(ListLifeCycleTypes.ON_LIST_AFTER_QUERY).subscribe((resp) => {
console.log('list after query', resp)
})
}}
actions={actions}
url={url}
pageSize={5}
>
{(props) => {
if (props.loading) return loading...
return props.dataSource.map((item, index) => {item.label}, {item.name})
}}
ReactDOM.render(
`
#### ListProvider
Usage
`typescript
import { ListProvider } from '@alist/react'
const List = (props) => {
const { children, ...others } = props
return
{(list: IList) => {
return
{props.children}
}}
}
`
#### FieldProvider
Usage
`typescript
import { FieldProvider } from '@alist/react'
const List = (props) => {
const { children, ...others } = props
return
{({ mode, validateConfig }) => {
return
{props.children}
}}
}
`
#### FilterProvider
Usage
`typescript
import { FilterProvider } from '@alist/react'
const List = (props) => {
const { children, ...others } = props
return
{({ filterInstance }, list) => {
return
{props.children}
}}
}
`
#### Consumer
Usage
`typescript
import { FilterProvider } from '@alist/react'
const List = (props) => {
const { children, ...others } = props
return
{(list) => {
return
{props.children}
}}
}
`
#### MultipleProvider
`typescript
import { MultipleProvider } from '@alist/react'
const List = (props) => {
const { id, pageSize, children, ...others } = props
return
{(list) => {
return
{props.children}
}}
}
`
#### PaginationProvider
`typescript
import { PaginationProvider } from '@alist/react'
const List = (props) => {
const { children, ...others } = props
return
{({ pageSize, currentPage, total, totlaPage, setCurrentPage, setPageSize }, list) => {
return
{props.children}
}}
}
`
#### TableProvider
`typescript
import { TableProvider } from '@alist/react'
const List = (props) => {
const { children, ...others } = props
return
{({ loading, dataSource }, list) => {
return
{props.children}
}}
}
`
#### useList
get a List instance, it already built in
Signature
`typescript`
type useList = (options: IListUIProps): IList
Usage
`typescript
import { useList } from '@alist/react'
const ListProvider: React.FC
const { children, ...others } = props || {};
const list = useList(others)
let element
if (typeof children === 'function') {
element = children(list)
} else {
element = children || React.Fragment
}
return (
{element}
)
}
`
#### useTable
get table data, it already built in
Signature
`typescript`
type useTable = (props: ITableProps = {}): ITableHook
Usage
`typescript
import { useTable } from '@alist/react'
const TableProvider: React.FC
const { children } = props
const { loading, dataSource, list } = useTable(props)
let element
if (typeof children === 'function') {
element = children({ dataSource, loading }, list)
} else {
element = children || React.Fragment
}
return element
}
`
#### useConsumer
get list data, it already built in
Signature
`typescript`
type useConsumer = (props: IConsumerProps): IList
Usage
`typescript
import { useConsumer } from '@alist/react'
const ConsumerProvider: React.FC
const { children } = props
const list = useConsumer(props)
let element
if (typeof children === 'function') {
element = children(list)
} else {
element = children || React.Fragment
}
return element
}
`
#### useFilter
get form instance, it already built in
Signature
`typescript`
type useFilter = (props: IFilterProps): IFilterHook
Usage
`typescript
import { useFilter } from '@alist/react'
const FilterProvider: React.FC
const { mode, children } = props
const { filterInstance, list } = useFilter(props)
let element
if (typeof children === 'function') {
element = children({
filterInstance,
}, list)
} else {
element = children || React.Fragment
}
return
{element}
}
`
#### useFilterItem
get field data, it already built in
Signature
`typescript`
type type useFilterItem = (props: IFilterItemProps): IFilterItemHook
Usage
`typescript
import { useFilterItem } from '@alist/react'
const FilterProvider: React.FC
const { mode, children } = props
const { validateConfig, mode } = useFilterItem(props)
let element
if (typeof children === 'function') {
element = children({
validateConfig, mode,
}, list)
} else {
element = children || React.Fragment
}
return element
}
`
#### usePagination
get pagination data, it already built in
Signature
`typescript`
type usePagination = (props: IPaginationProps = {}): IPaginationHook
Usage
`typescript
import { usePagination } from '@alist/react'
const PaginationProvider: React.FC
const { children } = props
const { list, pageData, setCurrentPage, setPageSize } = usePagination(props)
let element
if (typeof children === 'function') {
element = children({
...pageData,
setCurrentPage,
setPageSize,
}, list)
} else {
element = children || React.Fragment
}
return element
}
`
#### useMultipleProvider
get multiple list data, it already built in
Signature
`typescript`
type useMultipleProvider = (props: IMultipleProps): IMultipleHook
Usage
`typescript
import { useMultipleProvider } from '@alist/react'
const MultipleProvider: React.FC
const { children } = props
const { list, id, pageSize } = useMultipleProvider(props)
let element
if (typeof children === 'function') {
element = children(list)
} else {
element = children || React.Fragment
}
return element
}
`
> The API is fully inherited from @alist/core. The specific API of @alist/react is listed below.
---
#### createListActions
> Return IListActions
Signature
`typescript`
createListActions(): IListActions
Usage
`typescript
import { createListActions } from '@alist/react'
const actions = createListActions()
console.log(actions.getPageData())
console.log(actions.getDataSource())
`
#### createAsyncListActions
> Return IListAsyncActions
Signature
`typescript`
createAsyncListActions(): IListAsyncActions
Usage
`typescript
import { createAsyncListActions } from '@alist/react'
const actions = createAsyncListActions()
console.log(actions.getPageData().then(val => console.log(val))
console.log(actions.getDataSource().then(val => console.log(val))
`
#### ListEffectHooks
> Return all @alist/core lifeCycles hook which can be subscribe
Usage
`tsx
import { ListEffectHooks, ListProvider } from '@alist/react'
const {
/**
* List LifeCycle
**/
// List pre-initialization trigger
onListWillInit$,
// List initialization trigger
onListInit$,
} = ListEffectHooks
const App = () => {
return (
onListInit$().subscribe(() => {
console.log('initialized')
})
}}
>
...
)
}
`
#### createListEffectHook
> Custom your own hook by this api
Signature
`typescript`
(type: string): Observable
Usage
`jsx
import { ListProvider, createListEffectHook, createListActions } from '@alist/react'
const actions = createListActions()
const diyHook1$ = createListEffectHook('diy1')
const diyHook2$ = createListEffectHook('diy2')
const App = () => {
return (
effects={() => {
diyHook1$().subscribe((payload) => {
console.log('diy1 hook triggered', payload)
})
diyHook2$().subscribe((payload) => {
console.log('diy2 hook triggered', payload)
})
}}
>
)
}
ReactDOM.render(
`
> The Interfaces is fully inherited from @alist/core. The specific Interfaces of @alist/react is listed below.
---
#### IListMode
`typescript`
declare enum ModeType {
DATASOURCE = "dataSource",
URL = "url",
QUERY = "query"
}
declare type IListMode = ModeType.DATASOURCE | ModeType.URL | ModeType.QUERY;
#### IList
`typescript`
interface IList {
// set dataSource raw data
getDataSource: () => IListDataSource;
// set dataSource raw data
setDataSource: (data: IListDataSource) => void;
// set dataSource pagninated data
setPaginationDataSource: (data: IListDataSource) => void;
// set dataSource pagninated data
getPaginationDataSource: () => IListDataSource;
// get mode: dataSource | url | mutliple
getMode: () => IListMode;
// get search area data
getFilterData: () => IListFilterData;
// set search area data
setFilterData: (data: IListFilterData) => void;
// get uform instance
getFilterInstance: () => any;
// get uform instance construct params
getFilterProps: () => IFilterInitProps;
// set uform instance
setFilterInstance: (form?: any) => void;
// get pagination data
getPageData: () => IListPageData;
// set pagination data
setPageData: (data: IListPageData) => void;
// get multiple data which enable in multiple mode
getMultipleData: () => IListMultipleData;
// set multiple data which enable in multiple mode
setMultipleData: (data: IListMultipleDataParams) => void;
// set pageSize of multiple data which enable in multiple mode
setMultiplePageSize: (data: IListMultiplePageSize) => void;
// get validate config of search area
getValidateConfig: () => IListKVMap
// set validate config of search area
setValidateConfig: (validateConfig?: IListKVMap
// clear search area data
clear: () => void;
// request
search: () => void;
// reset search area data
reset: () => void;
//
refresh: () => void;
// set loading status of list
setLoading: (loading: boolean, fnOpts?: IListFunctionOptions) => void;
// get loading status of list
getLoading: () => boolean;
// set url
setUrl: (url: string, fnOpts?: IListFunctionOptions) => void;
// customize query
setQuery: (query: IListQuery, fnOpts?: IListFunctionOptions) => void;
// set params which will automatically change url params
setParams: (params: IListParams, fnOpts?: IListFunctionOptions) => void;
// get from url params
getParams: () => IListParams;
// set current page
setCurrentPage: (currentPage: number, fnOpts?: IListFunctionOptions) => void;
// set page size
setPageSize: (pageSize: number) => void;
// trigger list effects or customize effects
notify: (type: ListLifeCycleTypes, paylaod?: any) => void;
// triggered when lifeCycle function been notified
on: (key: EventType, cb?: IListEvent) => void;
// remove listening function
removeListener: (key: EventType, cb?: IListEvent) => void;
}
#### IListActions
`typescript`
export interface IListActions {
getDataSource: () => IListDataSource,
setDataSource: (data: IListDataSource) => void,
setPaginationDataSource: (data: IListDataSource) => void,
getPaginationDataSource: () => IListDataSource,
getMode: () => IListMode,
getFilterData: () => IListFilterData,
setFilterData: (data: IListFilterData) => void,
getFilterInstance: () => any,
getFilterProps: () => IFilterInitProps,
setFilterInstance: (form?: any) => void,
getPageData: () => IListPageData,
setPageData: (data: IListPageData) => void,
getMultipleData: () => IListMultipleData,
setMultipleData: (data: IListMultipleDataParams) => void,
setMultiplePageSize: (data: IListMultiplePageSize) => void,
getValidateConfig: () => IListKVMap
setValidateConfig: (validateConfig?: IListKVMap
clear: () => void,
search: () => void,
reset: () => void,
refresh: () => void,
setLoading: (loading: boolean, fnOpts?: IListFunctionOptions) => void,
getLoading: () => boolean,
setUrl: (url: string, fnOpts?: IListFunctionOptions) => void,
setQuery: (query: IListQuery, fnOpts?: IListFunctionOptions) => void,
setParams: (params: IListParams, fnOpts?: IListFunctionOptions) => void,
getParams: () => IListParams,
setCurrentPage: (currentPage: number, fnOpts?: IListFunctionOptions) => void,
setPageSize: (pageSize: number) => void,
on: (key: EventType, cb?: IListEvent) => void
notify: (type: ListLifeCycleTypes, paylaod?: any) => void,
removeListener: (key: EventType, cb?: IListEvent) => void,
}
#### IListAsyncActions
`typescript`
export interface IListAsyncActions {
getDataSource: () => Promise
setDataSource: (data: IListDataSource) => Promise
setPaginationDataSource: (data: IListDataSource) => Promise
getPaginationDataSource: () => Promise
getMode: () => Promise
getFilterData: () => Promise
setFilterData: (data: IListFilterData) => Promise
getFilterInstance: () => Promise
getFilterProps: () => Promise
setFilterInstance: (form?: any) => Promise
getPageData: () => Promise
setPageData: (data: IListPageData) => Promise
getMultipleData: () => Promise
setMultipleData: (data: IListMultipleDataParams) => Promise
setMultiplePageSize: (data: IListMultiplePageSize) => Promise
getValidateConfig: () => Promise
setValidateConfig: (validateConfig?: IListKVMap
clear: () => Promise
search: () => Promise
reset: () => Promise
refresh: () => Promise
setLoading: (loading: boolean, fnOpts?: IListFunctionOptions) => Promise
getLoading: () => Promise
setUrl: (url: string, fnOpts?: IListFunctionOptions) => Promise
setQuery: (query: IListQuery, fnOpts?: IListFunctionOptions) => Promise
setParams: (params: IListParams, fnOpts?: IListFunctionOptions) => Promise
getParams: () => Promise
setCurrentPage: (currentPage: number, fnOpts?: IListFunctionOptions) => Promise
setPageSize: (pageSize: number) => Promise
on: (key: EventType, cb?: IListEvent) => Promise
notify: (type: ListLifeCycleTypes, paylaod?: any) => Promise
removeListener: (key: EventType, cb?: IListEvent) => Promise
}
#### IListUIProps
`typescript`
interface IListUIProps {
dataSource?: any;
validateConfig?: IListKVMap
url?: string;
method?: IListQueryMethod;
params?: any;
paramsFields?: string | string[];
pageSize?: number;
currentPage?: number;
total?: number;
totalPages?: number;
autoLoad?: boolean;
defaultFilterValues?: any;
multiple?: boolean;
filterConfig?: any;
query?: IListQuery;
formatBefore?: (queryData: IListQueryData) => any | void;
formatAfter?: (response: any) => any | void;
formatFilter?: (filterData: IListFilterData) => any | void;
lifeCycles?: ListLifeCycle[];
effects?: IListEffect,
actions?: any,
afterInitialized?: (list: IList) => void
}
#### ITableProps
`typescript`
interface ITableProps {
children?: React.ReactElement | ((...args: any) => React.ReactElement),
multipleId?: string
}
#### ITableHook
`typescript`
interface ITableHook {
list: IList,
dataSource: any[],
loading: boolean,
}
#### IFilterHook
`typescript`
interface IFilterHook {
list: IList,
filterInstance: IForm,
}
#### IFilterItemHook
`typescript`
interface IFilterItemHook {
list: IList,
validateConfig: IListKVMap
}
#### IPaginationHook
`typescript`
interface IPaginationHook {
list: IList,
setCurrentPage: (page: number) => void,
setPageSize: (pageSize: number) => void,
pageData: IListPageData,
}
#### IMultipleHook
`typescript``
interface IMultipleHook {
list: IList,
id: string,
pageSize: number,
}