作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Hooks于2019年2月引入React,以提高代码的可读性. 我们已经讨论过React的hook in 前面的文章但是这次我们要研究的是钩子是如何与打印稿一起工作的.
在hook出现之前,React组件有两种风格:
它们的自然用途是构建复杂的 容器组件 用类和简单 表象的 具有纯函数的组件.
容器组件处理状态管理和对服务器的请求, 本文将调用哪一个 副作用. 状态将通过props传播给容器子节点.
但随着代码的增长, 功能组件倾向于转换为容器组件.
将功能组件升级为更智能的组件并不那么痛苦, 但这是一项耗时且令人不快的任务. 此外,区分展示者和容器 非常严格的 不受欢迎了.
钩子可以兼而有之, 因此生成的代码更加统一,并且几乎具有所有的优点. 下面是一个向处理报价签名的小组件添加本地状态的示例.
//将签名置于本地状态,并在签名更改时切换签名
函数QuotationSignature({quote}) {
const [signed, setSigned] = useState(引号.signed);
useEffect(() => {
fetchPost(“报价/ ${报价.} /标志”)
}, [signed]); // effect will be fired when signed changes
return <>
{setSigned(!signed)}}/>
Signature
>
}
这有一个很大的好处——编码 打印稿 用Angular很棒,但用React却臃肿. 然而,编码 用打印稿 React钩子 是一次愉快的经历.
打印稿是由微软设计的,在开发React时遵循了Angular的路径 Flow目前,美国正逐渐失去吸引力. 用朴素的打印稿编写React类是相当痛苦的,因为 开发人员反应 两个都要打 props
and state
尽管很多钥匙都是一样的.
这是一个简单的域对象. We make a 报价应用程序, with a Quotation
类型,在一些带有状态和道具的crud组件中进行管理. The Quotation
是否可以创建,其关联状态是否可以更改为已签名.
接口引用{
id:数量
标题:字符串;
行:QuotationLine []
价格:数量
}
接口QuotationState {
只读的报价:报价;
签名:布尔
}
接口QuotationProps {
报价:报价;
}
class QuotationPage extends Component {
// ...
}
但是想象一下QuotationPage现在将向服务器请求一个 id:如公司第678次报价. Well, 这意味着QuotationProps不知道那个重要的数字——它没有包装quote exactly. 我们必须在QuotationProps接口中声明更多的代码:
接口QuotationProps {
// ... quote的所有属性,除了id
标题:字符串;
行:QuotationLine []
价格:数量
}
我们在一个新类型中复制除了id以外的所有属性. Hm. 这让我想起了旧的Java,它涉及到编写一堆dto. 为了克服这个问题,我们将增加打印稿知识来绕过这个痛苦.
通过使用钩子,我们将能够摆脱以前的QuotationState接口. 为此,我们将把QuotationState拆分为状态的两个不同部分.
接口QuotationProps {
报价:报价;
}
函数QuotationPage({报价}:QuotationProps) {
const [quote, setquote] = useState(quote);
const [signed, setSigned] = useState(false);
}
通过拆分状态,我们不必创建新的接口. 本地状态类型通常由默认状态值推断.
带有钩子的组件都是函数. 因此,我们可以编写返回 FC
类型中定义的 反应图书馆. 该函数显式声明其返回类型,设置为props类型.
const QuotationPage : FC = ({quotation}) => {
const [quote, setquote] = useState(quote);
const [signed, setSigned] = useState(false);
}
显然,在React钩子中使用打印稿比在React类中使用打印稿更容易. 并且因为强类型对于代码安全来说是一种有价值的安全措施, 如果你的新项目使用了钩子,你应该考虑使用打印稿. 如果你想要一些打印稿,你绝对应该使用钩子.
有很多原因可以让你避免使用打印稿,不管你是否使用React. 但是如果你选择使用它,你一定也应该使用钩子.
在前面的React hooks的打印稿示例中, QuotationProps中仍然有number属性, 但目前还不清楚这个数字到底是多少.
打印稿给了我们一个长列表 实用程序类,其中三个将通过减少许多接口描述的噪音来帮助我们使用React.
Partial
: T的任意子键Omit
: T的所有键,除了键 x
Pick
: Exactly x, y, z
keys from T
在我们的案例中,我们想 Omit
省略引语的id. 我们可以动态地创建一个新的类型 type
keyword.
Partial
and Omit
在大多数类型语言如Java中不存在,但在前端开发中对表单示例有很大帮助. 它简化了输入的负担.
type QuotationProps= Omit;
函数QuotationPage({报价}:QuotationProps) {
const [quote, setquote] = useState(quote);
const [signed, setSigned] = useState(false);
// ...
}
现在我们有一个没有id的Quotation. 也许我们可以设计a Quotation
and PersistedQuotation
extends
Quotation
. 此外,我们将轻松解决一些经常性 if
or undefined
problems. 尽管变量不是完整的对象,我们还应该调用它吗? 这超出了本文的范围,但无论如何,我们将在后面提到它.
然而,现在我们确信我们不会传播一个我们认为有 number
. Using Partial
不带来所有这些保证,所以谨慎使用它.
Pick
有没有另一种方法可以动态声明类型,而不必声明新接口. 如果是组件,只需编辑Quotation标题:
type QuoteEditFormProps= Pick
Or just:
function QuotationNameEditor({id, title}:Pick){ ...}
不要评判我,我是领域驱动设计的忠实粉丝. 我没有懒到不想为新接口多写两行代码的地步. 我使用接口来精确地描述域名, 这些实用函数用于本地代码的正确性, 避免噪音. 读者会知道的 Quotation
是规范接口.
React团队始终将React视为一个功能框架. 他们使用类使组件能够处理自己的状态, 现在,钩子作为一种技术允许函数跟踪组件状态.
接口的地方{
城市:字符串,
国家:字符串
}
const initialState:Place = {
城市:“玫瑰花蕾”,
:“美国”
};
function reducer(state:Place, action):Partial {
开关(行动.type) {
例“城市”:
返回{city: action.有效载荷};
例“国家”:
返回{country: action.有效载荷};
}
}
函数PlaceForm() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
);
}
这是一个使用 Partial
是一个安全的好选择吗.
虽然一个函数可以被执行很多次,但是相关的 useReducer
钩子将只创建一次.
By naturally 从组件中提取减速器函数, 代码可以分为多个独立的函数,而不是一个类中的多个函数, 所有链接到类中的状态.
这显然对可测试性更好——有些函数处理JSX, 有行为的人, 其他具有业务逻辑的, and so on.
你(几乎)不再需要高阶分量了. 渲染道具 pattern 用函数更容易写吗.
因此,阅读代码更容易. 你的代码不是一个类/函数/模式流,而是一个函数流. However, 因为你的函数没有附加到对象上, 可能很难命名所有这些函数.
JavaScript很有趣,因为您可以向任何方向编写代码. 在打印稿中,你仍然可以使用 keyof
玩物体的钥匙. 你可以使用类型联合来创建一些不可读和不可维护的东西——不,我不喜欢那些. 您可以使用类型别名来假装字符串是UUID.
但你可以用零安全来做. 确保你的 tsconfig.json
has the “严格”:真的
option. 在项目开始之前检查它,否则您将不得不重构几乎每一行!
在代码中输入的类型级别存在争议. 您可以键入所有内容,也可以让编译器推断类型. 这取决于过滤器的配置和团队的选择.
此外,您仍然可能犯运行时错误! 打印稿比Java简单,并且避免了泛型的协方差/逆变问题.
In 这个动物/猫的例子,我们有一个动物列表,与猫列表相同. 不幸的是,这是第一行的合同,而不是第二行. 然后,我们将一只鸭子添加到Animal列表中,因此Cat列表为假.
接口动物{}
接口Cat扩展动物{
meow: () => string;
}
Const duck ={年龄:7};
Const felix = {
age: 12,
meow: () => "Meow"
};
const listOfAnimals: Animal[] = [duck];
const listOfCats: Cat[] = [felix];
MyApp() {
const [cats , setCats] = useState(listOfCats);
//事情是这样的:listOfCats被声明为一个动物[]
const [animals , setAnimals] = useState(listOfCats)
const [animal, setAnimal] = useState(鸭子)
return {
animals.Unshift (animal) //我们设置第一只猫是一只鸭子 !
setAnimals ([...[动物])// dirty forceUpdate
}
}>
第一只猫说{cats[0].meow()};
}
打印稿只有一个 bivariant 这是一种简单的泛型方法,可以帮助JavaScript开发人员采用. 如果正确地命名变量,就很少会添加 duck
to a listOfCats
.
此外,还有一个增加的建议 合同内外 协方差和逆变.
我最近回到Kotlin, 这很好, 类型语言, 正确输入复杂的泛型是很复杂的. 由于duck类型和双变量方法的简单性,打印稿没有那种泛型复杂性, 但你还有其他问题. 也许你在Angular中没有遇到很多问题, 为打印稿设计的, 但是你有React类.
打印稿可能是2019年的大赢家. 它获得了React,但也在用Node征服后端世界.Js及其键入旧库的能力相当简单 声明文件. 它埋葬了流动,尽管有些人离开了 一直使用ReasonML.
现在,我觉得hooks+打印稿比Angular更令人愉快、更高效. 六个月前我不会这么想的.
如果你使用钩子,打印稿现在对React来说非常好.
打印稿提供了代码的安全性. IDE给出了大多数代码错误,因此您在控制台中调试应用程序的时间更少.
React Hooks简化了代码演化和可维护性. Hooks还为一般问题提供了一组通用模式.
容器具有业务逻辑,而不是组件. 因此,与容器不同,组件可以在应用程序的不同部分重用,甚至可以在不同的应用程序中重用.
世界级的文章,每周发一次.
世界级的文章,每周发一次.