@ackee/lucas 中文文档教程
Lucas
一组 React 组件、高阶组件和我们在其他包中缺少的其他 UI 工具。
包的名称是指 福音传教士卢克 所有画家的赞助人。
Table of contents
Installation
使用 npm:
npm i -s @ackee/lucas
使用 yarn:
yarn add @ackee/lucas
API
Components
DataList
显示数据列表的组件,可选择滚动(但默认情况下滚动是打开的)。
Props
data
(object[]): List of objects that determines data supplied toRowComponent
.RowComponent
(ReactComponent|ReactNode): Component or Element used as a list row. If custom rootelement
prop no supplied, then it'stable
and so this component should havetr
as a root element to work properly.noDataMessage
(ReactNode [optional]): Message displayed when data list is empty. Default is'No data'
.scrollable
(boolean [optional]): Wheather scrollbars should be displayed when content overflow container. Default istrue
.element
(Component|string): Determine type of list root element.
Style
建议使用 widget-data-list__scrollbar-thumb
类名来设置滚动条缩略图的样式,因为默认情况下它是 rgba(0, 0, 0, 0)
。 下面是一个简单的拇指样式示例(但大多数情况下这就是您所需要的)
.widget-data-list__scrollbar-thumb {
background-color: grey;
border-radius: inherit;
}
示例
import { DataList } from '@ackee/lucas';
const data = [
{ id: 1, text: 'Text 1' },
{ id: 2, text: 'Text 2' },
{ id: 3, text: 'Text 3' },
];
const CustomRowComponent = ({ id, text }) => (
<tr>
<td style={rowStyle}>{id}</td>
<td style={rowStyle}>{text}</td>
</tr>
);
React.render(
<div>
<DataList data={data} RowComponent={CustomRowComponent} noDataMessage="Data list is empty" />
</div>
)
));
Prop types
childrenPropType
children
的道具类型形状。
示例
import { childrenPropType } from '@ackee/lucas'
MyComponent.propTypes = {
children: childrenPropType,
};
HOC
errorBoundary(ErrorComponent): BoundedComponent
用于设置错误边界的高阶组件。 实现与 React 作者描述的 非常相似。
Arguments
ErrorComponent
:显示错误的 React 组件。 接收
- prop
error
which is occured error - all the props supplied to
BoundedComponent
Returns
LOG_ERROR]() 操作
捕获子树中任何位置发生的任何意外错误并调用 [
// components/SimpleError.js
const SimpleError = ({ error }) => (
<div>
Error occured!:
<code>{error.message}</code>
</div>
);
// components/MainContent.js
const MainContent = () => (
<div>
<p>Error will be caught up</p>
{/* Click on the button bellow generates uncaught error */}
<button onClick={(e) => e.callNonExistingFunction()}>Do error</button>
</div>
);
// containers/MainContent.js
import { errorBoundary } from '@ackee/lucas';
import { compose } from 'redux';
import MainContent from '../components/MainContent';
compose(
errorBoundary(SimpleError),
)(MainContent);
loadable(LoaderComponent: Component, defaultText?: string): (MyComponent) => LoadableMyComponent
的组件代码>显示加载器 只是给装载机。
HOC 接受两个参数:
LoaderComponent
- component that is used as a loader, so it's displayed whileshowLoader
is truthydefaultText
[optional] - default text that is provided toLoaderComponent
unlessloaderText
prop is supplied to LoadableComponent
包装的可加载组件接受另外两个道具:
showLoader
- controls if loader is visibleloaderText
[optional] - text that is provided intoLoaderComponent
LoaderComponent
接收可加载内容(隐藏在加载器后面直到加载完成的组件)作为子项和两个道具:
show
- loader visibility flagtext
- loader text
Example
// components/Loader.jsx
const Loader = ({ children, show, text }) => (
<div>
{ children }
{ show && <div className="loader">{text}</div> }
</div>
);
export default Loader;
// containers/Users.js
import { loadable } from '@ackee/lucas';
import Users from '../components/Users';
import Loader from '../components/Loader';
export default compose(
connect(
state => ({
showLoader: isFetchingUsersSelector(state),
})
)
loadable(SimpleLoader),
)(Users);
makeDropzone(GraphicComponent): DropzoneComponent
高阶组件,方便制作带文件dropzone的文件上传组件。
Arguments
GraphicComponent
: React component that creates dropzone graphic.
Returns
接收两个额外属性的组件:
isMouseOver
(boolean): Determine if user drags with mouse over zone. Useful for changing dropzone style.uploadState
(FS): Actual state of file upload
File state
文件上传状态,可作为 HOC 的属性访问,因此 makeDropzone.FS
。
enum FS {
failed,
pending,
uploading,
uploaded
}
示例
// components/DropArea.js
const DropArea = ({ isMouseOver, uploadState }) => (
<div style={{ backgroundColor: isMouseOver ? 'yellow' : 'grey' }}>
<span className="button--blue button">
{
uploadState === makeDropzone.FS.uploaded || uploadState === makeDropzone.FS.failed
? 'Change'
: 'Select'
}
</span>
</div>
);
// containers/Dropzone.js
import { makeDropzone } from '@ackee/lucas';
import { compose } from 'redux';
import DropArea from '../components/DropArea';
export default compose(
makeDropzone,
)(DropArea);
// components/UploadImages.js
import containers from '@ackee/lucas';
import DropArea from '../containers/Dropzone';
const UploadImages = () => (
<Dropzone
onDrop={handleFilesDrop}
input={{
accept: 'image/png, image/jpeg',
multiple: boolean,
}}
/>
)
pure(equalityChecker): (UnpureComponent) => PureComponent
Makre 提供了纯组件——这意味着该组件在 props 发生变化之前不会重新渲染。
Arguments
equalityChecker
(function(prevProps, nextProps):bool [optional]) - Function that returns boolean which determines if prev props are equal to next props. You can provide your own eqaulity checker, if you don't provide equality checker, lodash'sisEqual
function is used.
退货: 接受 UnpureComponent
(应该针对无用的重新渲染进行优化的 React 组件)并返回 PureComponent
(仅当其 props 更改时才重新渲染的组件)的函数。 更改由相等检查器确定。
示例 - 自定义相等性检查器
import { pure } from '@ackee/lucas';
import { compose } from 'redux';
const customEqualityChecker = (props, nextProps) => {
return props.data.changableProp === nextProps.data.changableProp;
};
compose(
pure(customEqualityChecker),
)(DataConsumerComponent);
示例 - 默认相等性检查器
import { pure } from '@ackee/lucas';
import { compose } from 'redux';
compose(
pure(),
)(DataConsumerComponent);
Action types
记录操作类型
LOG_ERROR
import { actionTypes } from '@ackee/lucas';
import { takeEvery } from 'redux-saga/effects';
takeEvery(actionTypes.logging.LOG_ERROR, function* (action) {
const { error, extra } = action;
console.log(error, extra);
});
Lucas
Set of React componets, High order components and other UI tools we miss in other packages.
Name of package refers to Luke the evangelist the patron of all painters.
Table of contents
Installation
Using npm:
npm i -s @ackee/lucas
Using yarn:
yarn add @ackee/lucas
API
Components
DataList
Component that display list of data, optionally scrollable (but scrolling is turned on in default).
Props
data
(object[]): List of objects that determines data supplied toRowComponent
.RowComponent
(ReactComponent|ReactNode): Component or Element used as a list row. If custom rootelement
prop no supplied, then it'stable
and so this component should havetr
as a root element to work properly.noDataMessage
(ReactNode [optional]): Message displayed when data list is empty. Default is'No data'
.scrollable
(boolean [optional]): Wheather scrollbars should be displayed when content overflow container. Default istrue
.element
(Component|string): Determine type of list root element.
Style
It's recommended to style scrollbar thumb using widget-data-list__scrollbar-thumb
class name, because in default it's rgba(0, 0, 0, 0)
. Below is a simple example of styling thumb (but most time it's all you need)
.widget-data-list__scrollbar-thumb {
background-color: grey;
border-radius: inherit;
}
Example
import { DataList } from '@ackee/lucas';
const data = [
{ id: 1, text: 'Text 1' },
{ id: 2, text: 'Text 2' },
{ id: 3, text: 'Text 3' },
];
const CustomRowComponent = ({ id, text }) => (
<tr>
<td style={rowStyle}>{id}</td>
<td style={rowStyle}>{text}</td>
</tr>
);
React.render(
<div>
<DataList data={data} RowComponent={CustomRowComponent} noDataMessage="Data list is empty" />
</div>
)
));
Prop types
childrenPropType
Prop type shape for children
.
Example
import { childrenPropType } from '@ackee/lucas'
MyComponent.propTypes = {
children: childrenPropType,
};
HOC
errorBoundary(ErrorComponent): BoundedComponent
High order component for setting error boundaries up. Implementation is very similar to that described by React authors.
Arguments
ErrorComponent
: React component that shows the error. Receives
- prop
error
which is occured error - all the props supplied to
BoundedComponent
Returns
Component that catch any unexpected error that occured anywhere in subtree and invoke [LOG_ERROR
]() action
Example
// components/SimpleError.js
const SimpleError = ({ error }) => (
<div>
Error occured!:
<code>{error.message}</code>
</div>
);
// components/MainContent.js
const MainContent = () => (
<div>
<p>Error will be caught up</p>
{/* Click on the button bellow generates uncaught error */}
<button onClick={(e) => e.callNonExistingFunction()}>Do error</button>
</div>
);
// containers/MainContent.js
import { errorBoundary } from '@ackee/lucas';
import { compose } from 'redux';
import MainContent from '../components/MainContent';
compose(
errorBoundary(SimpleError),
)(MainContent);
loadable(LoaderComponent: Component, defaultText?: string): (MyComponent) => LoadableMyComponent
High order component that wraps your content component with supplied loader and pass prop showLoader
just to the loader.
HOC accepts two arguments:
LoaderComponent
- component that is used as a loader, so it's displayed whileshowLoader
is truthydefaultText
[optional] - default text that is provided toLoaderComponent
unlessloaderText
prop is supplied to LoadableComponent
Wrapped loadable component accepts two more props:
showLoader
- controls if loader is visibleloaderText
[optional] - text that is provided intoLoaderComponent
LoaderComponent
receives loadable content (the component(s) hidden behind loader until load finish) as a children and two props:
show
- loader visibility flagtext
- loader text
Example
// components/Loader.jsx
const Loader = ({ children, show, text }) => (
<div>
{ children }
{ show && <div className="loader">{text}</div> }
</div>
);
export default Loader;
// containers/Users.js
import { loadable } from '@ackee/lucas';
import Users from '../components/Users';
import Loader from '../components/Loader';
export default compose(
connect(
state => ({
showLoader: isFetchingUsersSelector(state),
})
)
loadable(SimpleLoader),
)(Users);
makeDropzone(GraphicComponent): DropzoneComponent
High order component for easy making of file upload component with file dropzone.
Arguments
GraphicComponent
: React component that creates dropzone graphic.
Returns
Component that receives two extra props:
isMouseOver
(boolean): Determine if user drags with mouse over zone. Useful for changing dropzone style.uploadState
(FS): Actual state of file upload
File state
File upload state, accessible as a property of HOC, so makeDropzone.FS
.
enum FS {
failed,
pending,
uploading,
uploaded
}
Example
// components/DropArea.js
const DropArea = ({ isMouseOver, uploadState }) => (
<div style={{ backgroundColor: isMouseOver ? 'yellow' : 'grey' }}>
<span className="button--blue button">
{
uploadState === makeDropzone.FS.uploaded || uploadState === makeDropzone.FS.failed
? 'Change'
: 'Select'
}
</span>
</div>
);
// containers/Dropzone.js
import { makeDropzone } from '@ackee/lucas';
import { compose } from 'redux';
import DropArea from '../components/DropArea';
export default compose(
makeDropzone,
)(DropArea);
// components/UploadImages.js
import containers from '@ackee/lucas';
import DropArea from '../containers/Dropzone';
const UploadImages = () => (
<Dropzone
onDrop={handleFilesDrop}
input={{
accept: 'image/png, image/jpeg',
multiple: boolean,
}}
/>
)
pure(equalityChecker): (UnpureComponent) => PureComponent
Makre provided component pure - it means that component not rerender until it's props change.
Arguments
equalityChecker
(function(prevProps, nextProps):bool [optional]) - Function that returns boolean which determines if prev props are equal to next props. You can provide your own eqaulity checker, if you don't provide equality checker, lodash'sisEqual
function is used.
Returns: Function that accepts UnpureComponent
(React component that should be optimilized for useless rerenderes) and return PureComponent
(component that rerender only if their props change). Change is determined either by equality checker.
Example - custom equality checker
import { pure } from '@ackee/lucas';
import { compose } from 'redux';
const customEqualityChecker = (props, nextProps) => {
return props.data.changableProp === nextProps.data.changableProp;
};
compose(
pure(customEqualityChecker),
)(DataConsumerComponent);
Example - default equality checker
import { pure } from '@ackee/lucas';
import { compose } from 'redux';
compose(
pure(),
)(DataConsumerComponent);
Action types
Logging action types
LOG_ERROR
import { actionTypes } from '@ackee/lucas';
import { takeEvery } from 'redux-saga/effects';
takeEvery(actionTypes.logging.LOG_ERROR, function* (action) {
const { error, extra } = action;
console.log(error, extra);
});