03-函数式组件
在之前我们学习Vue中定义组件的方式常见是通过(SFC)即单文件组件,每个.vue 结尾的文件就是一个独立的组件。 然后通过拼积木的方式把这些组件组合成一个网页。
而在 react 中定义组件最简单的方式就是编写 JavaScript 函数:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
该函数是一个有效的 React 组件,因为它接收唯一带有数据的 "props"(代表属性)对象与并返回一个 React 元素。这类组件被称为 "函数组件",因为它本质上就是 JavaScript 函数。
如果JSX标签仅有一行,也可以省略括号。
这里虽然我们编写的是JavaScript函数,但是函数体中返回的内容确跟我们认识的JavaScript有蛮大差异的。 这部分代码叫 jsx,它是一种内置的 DSL(领域特定语言) 在react 中跟Vue 一样会通过内部的编译器把jsx 解析为浏览器可识别的DOM。
为什么使用jsx?
React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。
React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为"组件" 的松散耦合单元之中,来实现关注点分离。
React 不强制要求使用 JSX,但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用。它还可以使 React 显示更多有用的错误和警告消息。
不使用 JSX 的代码:
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(Hello, {toWhat: 'World'}, null));
这种方式是通过class 定义 render function(渲染函数),在渲染函数中返回 virtual DOM。
这里我告诉大家手写render function 的方式跟贴近编译器,所以性能也更好。 react 编译器最终也是把 jsx 编译成 React.createElement 格式,通过参数来表述一个组件的形态。 虽然这种方式的性能更好但是放弃了灵活性,一但是组件结构赋值,涉及到大量的props,事件绑定 ... 就很难保持清醒的头脑继续写代码。
再来看jsx !!!
再来看jsx !!!
再来看jsx !!!
在 JSX 中嵌入表达式
在下面的例子中,我们声明了一个名为 name 的变量,然后在 JSX 中使用它,并将它包裹在大括号中:
const name = '老王';
const element = <h1>Hello, {name}</h1>;
在 JSX 语法中,你可以在大括号内放置任何有效的 JavaScript 表达式。例如,2 + 2,user.firstName 或 formatName(user) 都是有效的 JavaScript 表达式。
在下面的示例中,我们将调用 JavaScript 函数 formatName(user) 的结果,并将结果嵌入到元素中。
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
JSX 也是一个表达式
在编译之后,JSX 表达式会被转为普通 JavaScript 函数调用,并且对其取值后得到 JavaScript 对象。 也就是说,你可以在 if 语句和 for 循环的代码块中使用 JSX,将 JSX 赋值给变量,把 JSX 当作参数传入,以及从函数中返回 JSX:
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
JSX 中指定属性
你可以通过使用引号,来将属性值指定为字符串字面量:
const element = <a href="https://www.reactjs.org"> link </a>;
也可以使用大括号,来在属性值中插入一个 JavaScript 表达式:
const element = <img src={user.avatarUrl}></img>;
在属性中嵌入 JavaScript 表达式时,不要在大括号外面加上引号。你应该仅使用引号(对于字符串值)或大括号(对于表达式)中的一个,对于同一属性不能同时使用这两种符号。
就一个字 灵活!!!!
就一个字 灵活!!!!
就一个字 灵活!!!!
完整的示例代码:
components -> ColumnList 组件开发
const FunComName:React.FC =()=>{
return (
<div></div>
)
}
Typescript中,React 的组件可以定义为 函数(React.FC<>
)React.FC
是函数式组件,是在TypeScript使用的一个 泛型 。FC是FunctionComponent的缩写,React.FC
可以写成 React.FunctionComponent
。
当我们把鼠标指向React.FC的时候可以看到这个类型函数接收一个泛型变量P, 而这个P应用于props的类型,你可以不用显示的声明props类型。
type React.FC<P = {}> = React.FunctionComponent<P>
React.FC
包含了 PropsWithChildren 的泛型,不用显式的声明 props.children 的类型。
当然它也可以是一个interface。
import React, { useState } from 'react';
interface IProps {
test?: any;
}
const Index: React.FC<IProps> = (props) => {
let [count, setCount] = useState(0);
return(
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Click</button>
</div>
);
};
export default Index;
接下来我们就考虑如果要显示一个 ColumnList 应该需要包含哪些数据,对于数据我们可以创建一个interface来定义。
interface ColumnProps {
title: string;
url: string;
description: string;
}
const FunComName:React.FC<ColumnProps> =(props)=>{
const url = props.url;
return (
<div></div>
)
}
export default FunComName;
接下来我们就课可以在ColumnList 中去访问props的这些数据属性了。 我也可以使用es6的方式使用花括号来展开这个参数。
const FunComName:React.FC<ColumnProps> =({title, url, description})=>{
return (
<div></div>
)
}
接下来我们就可以完善模板填充对应的数据了。
const FunComName: React.FC<ColumnProps> = ({ title, url, description }) => {
return (
<li>
<img alt="logo" src={url} />
<h2>title</h2>
<p>Description</p>
</li>
);
};
但目前的问题是我们并没有获取到实际的数据,这里只是我们搭建的一个架子。
所以我们还得回到App.tsx 中去完善关于数据的传递 。
import React from "react";
import ListData from "./mock/ColumnList.json";
import ColumnList from "./components/ColumnList";
import "./App.css";
function App() {
return (
<ul>
{ListData.map((l) => (
<ColumnList title={l.title} url={l.url} description={l.description} />
))}
</ul>
);
}
export default App;
速生成react.fc 模板
在我们创建react 函数式组件中经常要使用到这个固定的模板,能不能通过快捷键来创建呢?
import React from 'react';
const ColumnList =()=>{
return (
<></>
)
}
export default ColumnList;
打开vscode,选中 文件 -> 首选项 -> 用户片段。
react.json文件
{
"Print to console": {
"prefix": "react17",
"body": [
"import React from 'react';",
"",
"const FunComName =()=>{",
" return (",
" <div></div>",
" )",
"}",
"",
"",
"export default FunComName;",
],
"description": "Log output to console"
}
}
prefix 快捷名称 / body 主题部分 / description 文件描述