ReactWheels04-02Icon组件上

Icon组件

icon.tsx

1
2
3
4
5
6
7
8
9
import React from 'react';

function Icon(){
return (
<span>icon</span>
)
}

export default Icon;

index.tsx

1
2
3
4
5
6
7
import ReactDOM from 'react-dom';
import React from 'react';
import Icon from './icon/icon';

ReactDOM.render(<div>
<Icon />
</div>, document.body);

为 Icon 添加 name属性

  • React.FunctionComponent 代表这是一个函数式组件
    1
    React.FunctionComponent<IconProps> 代表这个组件必须遵循 IconProps 里的属性也就是必须有name属性

icon.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
import React from 'react';

interface IconProps {
name: string;
}

const Icon:React.FunctionComponent<IconProps> = (props)=> {
return (
<span>{props.name}</span>
)
}

export default Icon;

index.tsx

1
2
3
4
5
6
7
import ReactDOM from 'react-dom';
import React from 'react';
import Icon from './icon/icon';

ReactDOM.render(<div>
<Icon name="qq"/>
</div>, document.body);

消除IDE的警告

1
2
3
4
5
6
# 为什么这样有警告
<Icon name="qq"></Icon>
# 上面的写法是 xml

# 而这里推荐的是这样,如果没有子内容就自闭和
<Icon name="qq"/>

如何现实 微信的 图标

  1. 打开 iconfont.cn 随便选个图标,账号登录,最后点svg下载
  2. 如何在一个组件里显示svg
    • 要改loader,因为webpack不认识svg
    • svg-sprite-loader
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      # 安装依赖
      yarn add svg-sprite-loader --dev

      # 修改webpack.config.js
      module:{
      rules:[
      {
      test: /\.svg$/,
      loader: 'svg-sprite-loader',
      }
      ]
      }

      # icon.tsx里
      import wechar from '../icons/wechat.svg'

      # 重新运行 yarn start
      失败了 因为 js认识 svg, ts不认识 svg

      # 重新声明 svg的类型让 ts认识
      新建 lib/types/custom.d.ts
      // 内容如下
      declare module '*.svg' {
      const content: any;
      export default content;
      }

      # 此时 ide里还是报错 ,修改 tsconfig.json

      "include": [
      "lib/**/*",
      "types/**/*"
      ]
      # 此时不报错了

路径里的 星星什么意思

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"lib/**/*",

如有如下目录
|a
|--1.js
|--2.js
|--b
|--|--3.js

如果写 a/* 就不会匹配 3.js

如果写 a/b/* 就只会匹配3.js而不会匹配 1.js 2.js

所以写 a/**/* 就是所有目录的 js

yarn start 页面警告了

1
2
3
4
5
6
7
8
9
10
react-dom.development.js:506 Warning: render(): Rendering components directly into document.body is discouraged, since its children are often manipulated by third-party scripts and browser extensions. This may lead to subtle reconciliation issues. Try rendering into a container element created for your app.


# 意思是 不能直接渲染在 document.body上
# 在 index.html里 写一个 <div id="root"></div>

# 修改 index.tsx
ReactDOM.render(<div>
<Icon name="qq"/>
</div>, document.querySelector('#root'));

如何渲染 svg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react';
import wechat from './icons/wechat.svg';

interface IconProps {
name: string;
}

const Icon:React.FunctionComponent<IconProps> = (props)=> {
return (
<svg>
<use xlinkHref={`#${props.name}`}/>
</svg>
)
}

export default Icon;

custom.d.ts有什么用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/types/custom.d.ts 内容如下
declare module '*.svg' {
const content: any;
export default content;
}

# 把 custom.d.ts 内容清空

# 我们如果引入 svg 以这样的方式 ,依然可以正常显示
import './icons/wechat.svg';
import './icons/qq.svg';
import './icons/alipay.svg';

# 但是修改成这样

import wechat from './icons/wechat.svg';

就报错了, 因为 一个 export default xxx 对应一个 import xxx from 'x'
就报错了, 因为 一个 export default xxx 对应一个 import xxx from 'x'
就报错了, 因为 一个 export default xxx 对应一个 import xxx from 'x'

# 而 custom.d.ts 里的这些 意思就是所有的.svg文件 默认导出一个东西
declare module '*.svg' {
const content: any;
export default content;
}

有一个现实问题 ,如果有100个svg,难道要写100个 import ‘xxx’;

importIcons.js

1
2
3
4
5
6
let importAll = (requireContext) => requireContext.keys().forEach(requireContext)
try {
importAll(require.context('./icons/', true, /\.svg$/))
} catch (error) {
console.log(error)
}

修改icon.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react';
import './importIcons';

interface IconProps {
name: string;
}

const Icon:React.FunctionComponent<IconProps> = (props)=> {
return (
<svg>
<use xlinkHref={`#${props.name}`}/>
</svg>
)
}

export default Icon;

tree-shaking是什么

1
2
3
4
5
6
7
8
9
10
11
12
# 到底我们应该
import A from 'a'
import B from 'b'
import C from 'c'

# 还是应该像刚才一样
importAll('./x')


第一个叫做静态引入(方便我们 tree-shaking)

第二个叫做非静态加载(写的时候方便)

比如你项目里依赖一个模块A,A里面有多个功能 a1/a2/a3 而你只用到了 a1 那么 a2/a3 则属于没有被依赖,

而 tree-shaking 则是把没有用到的依赖从打包里删掉。只留下真正用到的依赖。

tree-shaking的基础就是 静态引入

  • 非静态引入虽然方便,但是无法在后续使用 tree-shaking 来优化

代码链接

https://github.com/slTrust/react-gulu-test-3/tree/6c1bbb7b957d0090081215f9e9508279924ec8d1