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 文件描述