# @bem-react/core · [![npm (scoped)](https://img.shields.io/npm/v/@bem-react/core.svg)](https://www.npmjs.com/package/@bem-react/core) [![npm bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/@bem-react/core.svg)](https://bundlephobia.com/result?p=@bem-react/core)
Core package helps organize and manage components with [BEM modifiers](https://en.bem.info/methodology/key-concepts/#modifier) in React.
## Install
```
npm i -S @bem-react/core
```
## Usage
Let's say, you have an initial App file structure as follows:
```
App.tsx
Components/
Button/
Button.tsx
```
And you need to set up two optional types of buttons that will be different from the `Button.tsx`. _(In our example those will be Button of theme 'action' and Button of type 'link')_
You can handle those using _@bem-react/core_.
Follow the guide.
#### Step 1.
In your `Components/Button/index.tsx`, you define the type of props your button can get within the interface that extends **IClassNameProps** from '@bem-react/core' :
```ts
import { ReactType } from 'react'
import { IClassNameProps } from '@bem-react/core'
import { cn } from '@bem-react/classname'
export interface IButtonProps extends IClassNameProps {
as?: ReactType
}
export const cnButton = cn('Button')
```
#### Step 2.
Set up the **basic Button** variant which will be rendered if **no modifiers** props are set in the parent component.
Inside your `Components/Button/Button.tsx`:
```tsx
import React, { FC } from 'react'
import { IButtonProps, cnButton } from './index'
export const Button: FC<IButtonProps> = ({
children,
className,
as: Component = 'button',
...props
}) => (
<Component {...props} className={cnButton({}, [className])}>
{children}
</Component>
)
```
#### Step 3.
Set up the **optional withButtonTypeLink** and **optional withButtonThemeAction** variants that will be rendered if `{type: 'link'}` and/or `{theme: 'action'}` modifiers are set in the parent component respectively.
Inside your `Components/Button/` you add folders `_type/` with `Button_type_link.tsx` file in it and `_theme/` with `Button_theme_action.tsx` .
```
App.tsx
Components/
Button/
Button.tsx
index.tsx
+ _type/
+ Button_type_link.tsx
+ _theme/
+ Button_theme_action.tsx
```
Set up the variants:
**Note!** The second parameter in `withBemMod()` is the condition for this component to be applied.
**1.** In `Components/Button/_type/Button_type_link.tsx`
```tsx
import React from 'react'
import { withBemMod } from '@bem-react/core'
import { IButtonProps, cnButton } from '../index'
export interface IButtonTypeLinkProps {
type?: 'link'
href?: string
}
export const withButtonTypeLink = withBemMod<IButtonTypeLinkProps, IButtonProps>(
cnButton(),
{ type: 'link' },
(Button) => (props) => <Button {...props} as="a" />,
)
```
**2.** In `Components/Button/_theme/Button_theme_action.tsx`
```tsx
import { withBemMod } from '@bem-react/core'
import { cnButton } from '../index'
export interface IButtonThemeActionProps {
theme?: 'action'
}
export const withButtonThemeAction = withBemMod<IButtonThemeActionProps>(cnButton(), {
theme: 'action',
})
```
#### Step 4.
Finally, in your `App.tsx` you need **compose** only necessary the variants with the basic Button.
Be careful with the import order - it directly affects your CSS rules.
> **NOTE:** If you wanna use same modifiers with different values you should use `composeU` for getting correctly typings.
```tsx
import React, { FC } from 'react';
import { compose, composeU } from '@bem-react/core';
import { Button as ButtonPresenter } from './Components/Button/Button';
import { withButtonTypeLink } from './Components/Button/_type/Button_type_link';
import { withButtonThemeAction } from './Components/Button/_theme/Button_theme_action';
import { withButtonThemeDefault } from './Components/Button/_theme/Button_theme_default';
import './App.css';
const Button = compose(
composeU(withButtonThemeAction, withButtonThemeDefault),
withButtonTypeLink,
)(ButtonPresenter);
export const App: FC = () => (
<div className="App">
<Button>I'm basic</Button>
// Renders into HTML as: <button class="Button">I'm Basic</button>
<Button type="link" href="#stub">I'm type link</Button>
// Renders into HTML as: <a href="#stub" class="Button Button_type_link">I'm type link</a>
<Button theme="action">I'm theme action</Button>
// Renders into HTML as: <button class="Button Button_theme_action">I'm theme action</button>
<Button theme="action" type="link">I'm all together</Button>
// Renders into HTML as: <a class="Button Button_theme_action Button_type_link">I'm all together</a>
</div>
);
```
**Note!** The order of optional components composed onto ButtonPresenter is important: in case you have different layouts and need to apply several modifiers the **FIRST** one inside the compose method will be rendered!
E.g., here:
```tsx
export const Button = compose(
withButtonThemeAction,
withButtonTypeLink,
)(ButtonPresenter)
```
If your withButtonThemeAction was somewhat like
`<button className={className}>{children}</button>`
your JSX-component:
`<Button type="link" theme="action">Hello</Button>`
would render into HTML:
`<a class="Button Button_theme_action Button_type_link">Hello</a>`
## Use reexports for better DX
> **IMPORTANT:** use this solution if [tree shaking](https://webpack.js.org/guides/tree-shaking/) enabled
Example:
```
Block/Block.tsx
Block/Block@desktop.tsx
Block/_mod/Block_mod_val1.tsx
Block/_mod/Block_mod_val2.tsx
Block/_mod/Block_mod_val3.tsx
```
Create reexports for all modifers in intex files by platform: desktop, phone, amp, etc.
```ts
// Block/index.ts
export * from './Block'
export * from './Block/_mod'
// Block/desktop.ts
export * from './Block@desktop'
export * from './Block/_mod'
// Block/phone.ts
export * from './' // for feature if not created platform version
// Block/_mod/index.ts
export * from './Block_mod_val1.tsx'
export * from './Block_mod_val2.tsx'
export * from './Block_mod_val3.tsx'
```
Usage:
```ts
// App.tsx
import { Block as BlockPresenter, withModVal1 } from './components/Block/desktop'
const Block = withModVal1(BlockPresenter)
```
## Optimization. Lazy load for modifiers.
Solution for better code spliting with React.lazy and dynamic imports
> **NOTE** If your need SSR replace React.lazy method for load `Block_mod.async.tsx` module to [@loadable/components](https://www.smooth-code.com/open-source/loadable-components/) or [react-loadable](https://github.com/jamiebuilds/react-loadable)
```tsx
// Block/_mod/Block_mod.async.tsx
import React from 'react'
import { cnBlock } from '../Block'
import './Block_mod.css'
export const DynamicPart: React.FC = () => <i className={cnBlock('Inner')}>Loaded dynamicly</i>
// defualt export needed for React.lazy
export default DynamicPart
```
```tsx
// Block/_mod/Block_mod.tsx
import React, { Suspense, lazy } from 'react'
import { cnBlock } from '../Block'
export interface BlockModProps {
mod?: boolean
}
export const withMod = withBemMod<BlockModProps>(cnBlock(), { mod: true }, (Block) => (props) => {
const DynamicPart = lazy(() => import('./Block_mod.async.tsx'))
return (
<Suspense fallback={<div>Updating...</div>}>
<Block {...props}>
<DynamicPart />
</Block>
</Suspense>
)
})
```
Usage:
```ts
// App.tsx
import {
Block as BlockPresenter,
withMod
} from './components/Block/desktop';
const Block = withMod(BlockPresenter);
export const App = () => {
return (
{/* chunk with DynamicPart not loaded */}
<Block />
{/* chunk with DynamicPart loaded */}
<Block mod />
);
}
```
## Debug
To help your debug "@bem-react/core" support development mode.
For `<Button type="link" theme="action">Hello</Button>` (from the **Example** above), React DevTools will show:
```html
<WithBemMod(Button)[theme:action] ...>
<WithBemMod(Butto
没有合适的资源?快使用搜索试试~ 我知道了~
bem-react-core, React库与边界元法开发的核心库.zip
共76个文件
md:21个
json:17个
js:11个
需积分: 10 2 下载量 54 浏览量
2019-09-17
18:31:33
上传
评论
收藏 66KB ZIP 举报
温馨提示
bem-react-core, React库与边界元法开发的核心库 边界元反应核 这是什么?它是一个将反应的组成部分作为边界元的库。 它在通常的反应组件之上工作,并提供块声明。元素及其修饰符的API 。 与这里库创建的块和元素完全兼容任何反应组件: 块和元素可以使用任何其他响应组件 insi
资源推荐
资源详情
资源评论
收起资源包目录
bem-react-core.zip (76个子文件)
bem-react-master
CONTRIBUTING.ru.md 23B
.gitignore 98B
mocha.opts 142B
tsconfig.json 562B
README.md 17B
tsconfig.test.json 88B
lerna.json 302B
enzyme.config.js 759B
.prettierrc 181B
packages
classnames
.gitignore 16B
tsconfig.json 201B
README.md 554B
CHANGELOG.md 2KB
test
classnames.test.ts 537B
package.json 948B
index.js 201B
classnames.tsx 645B
eslint-plugin
README.md 762B
CHANGELOG.md 564B
tests
lib
rules
whitelist-levels-imports.js 3KB
docs
rules
whitelist-levels-imports.md 3KB
package.json 623B
index.js 118B
lib
rules
whitelist-levels-imports.js 2KB
di
.gitignore 8B
tsconfig.json 201B
README.md 5KB
CHANGELOG.md 6KB
test
di.test.tsx 12KB
package.json 1014B
di.tsx 3KB
index.js 185B
classname
.gitignore 15B
tsconfig.json 201B
classname.tsx 4KB
README.md 1KB
CHANGELOG.md 9KB
test
classname.test.ts 7KB
package.json 964B
index.js 199B
core
.gitignore 10B
tsconfig.json 201B
README.md 8KB
CHANGELOG.md 20KB
test
withBemMod.test.tsx 3KB
compose.test.tsx 1KB
package.json 1KB
core.tsx 7KB
index.js 189B
docs
ru
README.md 6KB
book.json 19B
CONTRIBUTING.md 4KB
LICENSE.txt 16KB
Introduction
Motivation.md 9KB
LANGS.md 47B
en
README.md 3KB
book.json 19B
CONTRIBUTING.md 2KB
LICENSE.txt 16KB
environment.d.ts 90B
README.ru.md 17B
mocha.config.js 163B
package.json 1KB
tslint.json 3KB
CONTRIBUTING.md 23B
scripts
.gitkeep 0B
rollup
build.js 4KB
LICENSE.ru.txt 19B
typedoc.js 320B
LICENSE.txt 19B
.commitlintrc.json 61B
.lintstagedrc 211B
.huskyrc 105B
.travis.yml 130B
.editorconfig 220B
.npmrc 30B
共 76 条
- 1
资源评论
weixin_38743968
- 粉丝: 404
- 资源: 2万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- Screenshot_20240427_031602.jpg
- 网页PDF_2024年04月26日 23-46-14_QQ浏览器网页保存_QQ浏览器转格式(6).docx
- 直接插入排序,冒泡排序,直接选择排序.zip
- 在排序2的基础上,再次对快排进行优化,其次增加快排非递归,归并排序,归并排序非递归版.zip
- 实现了7种排序算法.三种复杂度排序.三种nlogn复杂度排序(堆排序,归并排序,快速排序)一种线性复杂度的排序.zip
- 冒泡排序 直接选择排序 直接插入排序 随机快速排序 归并排序 堆排序.zip
- 课设-内部排序算法比较 包括冒泡排序、直接插入排序、简单选择排序、快速排序、希尔排序、归并排序和堆排序.zip
- Python排序算法.zip
- C语言实现直接插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序、归并排序、计数排序,并带图详解.zip
- 常用工具集参考用于图像等数据处理
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功