在组内有多次分享过有关于React最佳实践的一些应用场景,发现效果比推荐阅读内容或枯燥的解释原理来得更好。所以决定也在博客中采用这种方式:文章结合实例开发。

目录

内容

React与乐高

乐高的特点:

  • 有足够细致的基础部件
  • 拼装组合的可能性也足够丰富
  • 从小部件,不断拼搭,形成大单元

你记住这几点,用React去实现内容,其实也就是在做乐高。

  • react为你提供了基础的jsx,它如同乐高这种介质
  • react为你提供了各种钩子函数,以及jsx之间的组件语法,它就如同乐高的零件在拼接时的衔接方式
  • react允许我们定义一个只包含文本的组件,也可以允许定义一个复杂的组件;他们可能有状态,有可能没状态,总之,它们是组件,由这些组件我们可以组建出更加复杂的应用。

create-react-app

有句话怎么说来着?一句命令一时爽,一直命令,一直爽。哈哈。开个玩笑。当然有些人也可能就只会这个命令。好吧,我们就从这个命令开始。

npx create-react-app calculator

我们从一个计算器开始创建。

不想写样式,偷个懒

接下来我们先从静态架子开始实现,先别管动态的内容如何实现。因为这个过程也能有助于你消化和理解如何更优的实现这个内容。

写静态内容肯定就会有涉及样式,那我就推荐些tailwindcss。这个原子样式编程,关键可以帮我省时间啊。

  • npm install -D tailwindcss 安装一下;
  • npx tailwindcss init 初始化下配置,产生了tailwind.config.js
  • 修改下这个配置如下:
    module.exports = {
    content: ["./src/**/*.{html,js}"],
    theme: {
    extend: {},
    },
    plugins: [],
    }
  • index.css里面就写下面的内容即可
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
  • 然后就可以使用了
    <div className="bg-white"></div>

当然还有涉及使用font icon。 我这里以FontAwesome使用来说明。

  • 先安装核心
    npm i --save @fortawesome/fontawesome-svg-core
  • 安装需要icon包
    # Free icons styles
    npm i --save @fortawesome/free-solid-svg-icons
    npm i --save @fortawesome/free-regular-svg-icons
  • 安装react相关
    npm i --save @fortawesome/react-fontawesome
  • 使用:
    import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
    import { faSun, faMoon } from '@fortawesome/fontawesome-free-solid';
    <FontAwesomeIcon icon={faSun}  />
    <FontAwesomeIcon icon={faMoon}  />

兵马未动,“拆解”先行

“拆解”什么呢?拆解你要实现的内容。先不用急着写代码,脑袋瓜子里面先全面的把要实现的内容拆解一遍。

拆解深刻的理解其实可以理解为相似内容的拆解,动与静的拆解,公有与私有的拆解。先别急,停顿片刻。仔细想想我为什么这样说……

相似内容的拆解: 提炼相似点,提升服用度
动与静的拆解: 为后续组件优化做好铺垫
公有与私有的拆解: 公共的内容需要提炼出来,全局控制。

现在我们开始拆解这个计算器把。

如上图:

  • App.js 应用壳子
  • segment 就是零件目录了
    • Wrap.js 计算器壳子
    • ThemeSegment.js 计算器设置主题的模块
    • DisplaySegment.js 计算器的显示模块
    • DisplayJit.js 计算器-计算内容
    • DisplayResult.js 计算器-计算结果
    • DisplayHistory.js 计算器-计算历史
    • ControlSegment.js 计算器的输入模块
    • KeyWrap.js 计算器中输入模块中的按键模块

可以清楚的看到我这样划分的用意。其中按照功能块划分为了以上一些模块,其中KeyWrap是会被多次服用copy为不同的按键。其他模块则只有一个。但各自的功能不同,各司其职。所以这样的拆解是有意而为之的。

梳理数据

我们前面完成了静态内容,接下来我们得着手数据流了。计算器的数据流该如何抽象呢?先想想我们要做的这个计算器会涉及哪些功能?

  • 输入数字,符号,进行计算
  • 通过显示屏展示出输入的内容,计算出来的结果
  • 额外加入了一个皮肤主题切换的功能

那么我将它抽象为:

  • 主题切换功能
  • 计算器核心功能

那么一个个来剖析并实现。这里数据上我们先需要将数据进行理解,理解它们的属性,它们哪些是公共的,哪些是私有。

这里会涉及到全局数据,那么react中原生提供的相应能力就是context。当然你可能会说为什么不用redux之类的。不要忘记,我们现在是主要在于借助实践理解react,所以对于一些核心点,尽可能先从原生的api来使用。

所以我这里通过context来定义全局“数据流”, 为了方便引用,我统一将这类全局的数据流放在config.js中。

  • 主题切换功能,公共属性。主题控件负责接受输入,产生相应数据,作用于全局中的各个组件中的颜色,当然也作用于主题控件自身的交互效果。

    定义一个ThemeContext, 负责读写主题的值;
    再定一个GetThemeColor, 根据当前主题的值产出具体的颜色值;
    最后定义ThemeColorMap, 暗黑和纯白两套颜色值;

    //定义
    const ThemeContext = createContext('theme')
    const ThemeColorMap = {
        bg:[" bg-white "," bg-black "],
        controlbg: [" bg-slate-100 ", " bg-slate-900 "],
        keybg: [" bg-slate-200 ", " bg-slate-950 "],
        text:[" text-gray-500 ", " text-gray-400 "],
        btnactive: [" text-black ", " text-white "] 
    }
    const GetThemeColor = (type, theme)=>{
        return ThemeColorMap[type][(theme==="light"?0:1)]
    }
    //赋值
    const [ theme, setTheme ] = useState("light")
    <ThemeContext.Provider value={{theme,setTheme}}>
        ...
    </ThemeContext.Provider>
    
    //使用
    const themeObj = useContext(ThemeContext);
     <div onClick={()=>themeObj.setTheme("light")} className="cursor-pointer mx-2" >
            <FontAwesomeIcon icon={faSun} className={classNames({
                [GetThemeColor("btnactive", themeObj.theme)] : themeObj.theme === "light",
                [GetThemeColor("text", themeObj.theme)]: themeObj.theme !== "light"
            })}/>
            ...
     </div>
  • 计算器功能,公共属性。输入数字,运算符,通过我们后续的将编写具体逻辑,将这些输入进行效果,然后产出结果。

    先计算器定一个CalculatorContext,这个里面我们需要认真分析下,所需要涉及的读写内容。

    //仔细分析计算器功能, 细化功能逻辑,则定义如下读写机制
    //计算器运算,用于运算的,例如除以是 /
    const [ cInput, setCInput ] = useState("")
    //计算器运算显示,用于显示运算的内容,例如除以是 ÷
    const [ cInputDisplay, setCInputDisplay ] = useState("")
    //计算器运算历史
    const [ cHistory, setCHistory ] = useState([])
    //计算器的输入栈。我们还需要一个输入的顺序记录**计算器的输入栈**
    const [ inputStack, setInputStack ] = useState([])
    
    //包裹
    <CalculatorContext.Provider value={{
                cInput, setCInput,
                cInputDisplay, setCInputDisplay,
                cHistory, setCHistory,
                inputStack, setInputStack
            }}>
                <ThemeSegment />
                <DisplaySegment />
                <ControlSegment />
     </CalculatorContext.Provider>

    接下来就是

    DisplayHistory上面用于显示历史

    显示多少条历史呢?通过全局配置管理它,config.js里面加入一个HistoryNum

    DisplayJit, 显示需要运算的内容

    DisplayResult, 显示运算的结果

    可能运算内容存在执行时意外错误,catch一下。

    KeyWrap,输入键。这个里面承载的内容会最多。

    • 它会被复用,按照不同的传入值,赋予不同的功能含义
    • 它的不同功能,在被触发后,也需要提供相应的逻辑来应付整体的执行

    因此它的内容就大致是2块内容,UI + 输入时每一步的核心逻辑。
    UI:

    输入时的逻辑:

    const clickBtnHandler = ()=>{
        //每一步输入的核心逻辑。有兴趣后续可以自行查看源代码。
    }

总结归纳

我们做了这个,实际上就主要应用到了以下几块内容:

  • 组件化思维理解业务实现,时刻牢记,一切皆组件
  • 如何引用tailwindcss
  • 如何使用fontIcon
  • context的使用
  • useState
  • useContext

以上的每个概念似乎都不困难。我们先从这个最简单的实例着手理解react的应用。各位慢慢细品。码字不易,各位按需自行阅读。


0 条评论

发表回复

Avatar placeholder

您的邮箱地址不会被公开。 必填项已用 * 标注

粤ICP备2023023347号-1
error: Content is protected !!