这一次,我们将讨论模式、模式和模式。Context``````Presentational and Container Components``````Compound Components

上下文

根据React文档

上下文提供了一种通过组件树传递数据的方法,而无需在每个级别手动传递道具。

简单地说,如果您有一个需要通过多个组件级别的全局状态,可以使用 。例如:如果您有一个会影响所有组件的组件,将简化该过程。Context``````theme``````Context

**注意。**使用时有一个潜在的障碍需要牢记:它可以降低组件的可重用性。数据将在作用域中可用,因此不能在 外部使用它。我找到了一个很棒的视频来解释这个问题, 并告诉你如何避免 “道具钻探” 。Context``````Context``````Provider``````Provider

让我们看一个上下文在行动的示例:

import React, { useContext, createContext } from “react”; import “./styles.css”; let data = { title: “Welcome” }; const Context = createContext();

export default function App() { return ( <Context.Provider value={data}>

</Context.Provider> ); }

const Card = () => { return (

); };

const CardItem = () => { return (

</div> ); };</p> <p>const Title = () => { const data = useContext(Context); return <h1>{data.title}</h1>; };</code></p> <p><svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on" _msthidden="1"><title _msthash="1041547" _msttexthash="419224" _msthidden="1">Enter fullscreen mode Exit fullscreen mode

正如我们在这个(基本)示例中看到的,我们有三个级别的组件,并且我们只使用最后一个级别的 。这样,我们不需要把道具传递给所有级别。data.title

有关上下文语法的一些提示

使用上下文时,我总是应用此语法。然而,当我再次写的时候,我发现一些事情:

  • 在"静态数据"(如示例)中,我们实际上不需要 。我们可以自己履行这一职能:Provider

let data = { title: “Welcome” }; const Context = createContext(data);

export default function App() { return (

); }

Enter fullscreen mode Exit fullscreen mode

在比例的另一端,我们可以使用 而不是 , 像这样:Customer``````useContext

const Title = () => { return (<Context.Consumer> {(data) =>

{data.title}

} </Context.Consumer>); };

Enter fullscreen mode Exit fullscreen mode

演示和容器组件

这些组件(也称为 )是最著名的React模式之一。React 文档中没有引用它们,但 Dan Abramov 的文章提供了出色的指南。Smart And Dumb Components

简单地说,请参阅业务逻辑组件与 UI 视图的分离。Presentational And Container Components

让我们看看另一个场景:

  • 我们需要构建一个组件。Card
  • 在卡内,我们还有三个其他组件: 和 。Title``````Image``````Button
  • 单击后,该按钮将更改图片。

在开始处理组件之前,让我们创建两个文件夹:“演示"和"容器”。现在,让我们构建三个组件:Presentational

标题.js :

import React from “react”; export default function Title(props) { const { children, …attributes } = props; return <h1 {…attributes}>{children}; }

Enter fullscreen mode Exit fullscreen mode

图片.js :

import React from “react”; export default function Image(props) { const { src, alt } = props || {}; return {alt}; }

Enter fullscreen mode Exit fullscreen mode

按钮.js :

import React from “react”; export default function Button(props) { const { children, …attributes } = props; return <button {…attributes}>{children}; }

Enter fullscreen mode Exit fullscreen mode

最后,我们可以在容器文件夹组件中生成,称为 。Card

卡.js :

import React, { useEffect, useState } from “react”; import Title from “../Presentational/Title”; import Image from “../Presentational/Image”; import Button from “../Presentational/Button”;

export default function Card() { const [card, setCard] = useState({}); const [srcIndex, setSrcIndex] = useState(0);

useEffect(() => { setCard({ title: “Card Title”, image: { imagesArray: [ “https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTh87QN4DkF7s92IFSfm7b7S4IR6kTdzIlhbw&usqp=CAU”, “https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRjFnHdaH1i1m_xOaJfXTyq4anRFwRyCg1p1Q&usqp=CAU” ], alt: “card image” } }); }, []); const { image } = card; const changeImage = () => setSrcIndex((index) => index < image.imagesArray.length - 1 ? index + 1 : index - 1 ); return (

{card.title && card.title} <Image src={image && image.imagesArray[srcIndex]} alt={image && image.alt} />
); }

Enter fullscreen mode Exit fullscreen mode

如果您想查看完整的代码,请在此处查看

**注意!**你们很多人可能想知道为什么需要分成不同的组件。你可以把它们写在里面,对吗?Card

当我们分离组件时,我们可以在任何地方重用它们。但更重要的是,实现其他模式(如 或 )要容易得多。HOC``````Render Props

复合成分

在我看来,这是最复杂的模式之一,要理解,但我会尽量简单地解释它。

当我们谈论 时,最简单的方法是思考和使用HTML。您可以将它们视为具有基本功能的一组组件。有些状态是全局(如在模式中)或从容器(如模式)管理的。Compound Components``````select``````option``````context``````presentational and container

**复合成分**是这两者的混合体。这几乎就像他们每个人都有自己的状态, 他们从内部管理他们。

让我们看看下一个场景:

  • 我们需要开发和组件。Select``````Option
  • 我们希望生动,不同的颜色。Option
  • 颜色会影响颜色。Option``````Select

让我们看看示例:

应用程序.js

import React from “react”; import “./styles.css”; import Select from “./Select”; import Option from “./Option”;

export default function App() { return (

); }

Enter fullscreen mode Exit fullscreen mode

  • 渲染 和 组件。App``````Select``````Option
  • Option.Blue是"颜色组件"。Option.Red

选项.js

sdsdimport React, { useEffect } from “react”;

function Option(props) { const { children, style, value, setStyle } = props; useEffect(() => { if (setStyle) setStyle({ backgroundColor: style.backgroundColor }); }, [setStyle, style]); return ( ); }

Option.Blue = function (props) { props.style.backgroundColor = “blue”; return Option(props); };

Option.Red = function (props) { props.style.backgroundColor = “red”; return Option(props); }; export default Option;

Enter fullscreen mode Exit fullscreen mode

  • 在这里,您可以看到 和 的实现。显而易见,我们渲染组件,只需向道具添加属性。Option.Blue``````Option.Red``````Option
  • 来自 。它用于将所选颜色更改为所选选项的颜色。setStyle``````Select

选择.js

import React, { useState } from “react”;

export default function Select(props) { const { children } = props; const [style, setStyle] = useState({});

const findOptionActive = (e) => { const index = e.target.value * 1; const optionStyle = { …e.nativeEvent.target[index].style }; if (optionStyle) setStyle({ backgroundColor: optionStyle.backgroundColor }); };

const childrenWithProps = React.Children.map(children, (child, index) => { return React.cloneElement(child, { …child.props, value: index, setStyle: index === 0 && Object.keys(style).length === 0 ? setStyle : null, style: { backgroundColor: “white” } }); });

return ( ); }

Enter fullscreen mode Exit fullscreen mode

  • 现在,我们有一个具有 属性的 select 函数。onChange``````style
  • findOptionActive获取选项的样式并相应地更改选择的样式,
  • 魔法真的发生在.通常,当收到时,我们无法访问儿童道具 - 但在的帮助下,我们能做到。正如你所看到的,我们可以通过 , 和 作为道具.childrenWithProps``````Select``````children``````React.Children``````React.cloneElement``````value``````setStyle``````style

要获取完整代码,请单击此处。


See Also