React 学习项目1

React 学习

最近想学习一下react, 看到有一个比较有趣的网站, 本文记录用react简单实现它的过程

整体结构可以看两张截图


整体可分

  • Header
  • Body
  • Footer

效果如截图, 有一个商品的长列表, 假设比尔盖茨有1000亿美元, 看能够买什么东西.

下面根据部分拆解实现

左边是原站连接, 右边是语言切换按钮. 可以使用css的grid来横向展示多个div

function Header() {
  const onChangeLang = (isCn) => {
    i18n.changeLanguage(isCn ? "zh_CN" : "en");
  };
  return (
    <div className="Header"> 
      <div className="SourceSiteLike">...</div>
      <div className="LanguageSwitcher"><Switch onChange={changeLang}/></div>
    </div>
  );
}

// Header.css
.Header {
  ... 
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

采用i18nextreact-i18next实现国际化多语言切换

import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import zh_CN from "./zh_CH";  // json 文件存放的中文翻译键值对
import en from "./en";        // json 文件存放的英文翻译键值对

const resources = {
  zh_CN: {
    translation: zh_CN,
  },

  en: {
    translation: en,
  },
};
i18n.use(initReactI18next).init({
  resources,
  lng: "zh_CN",
  keySeparator: false,
  interpolation: { escapeValue: false },
});

export default i18n;

index.js 引用i18n, 即可使用withTranslationuseTranslation, 来对关键词做语言切换

Body

首先为了和HeaderFooter产生视觉差距, Body采用固定比例宽度, 并且margin-left{right}: auto;

  • Title

头像和游戏名字, 可以使用border-radius : 50%获得一个圆形头像.

接下来的MoneyBor,ProductListReceipt之间联系紧密, 采用Component组件Shop管理它们的共同状态

class Shop extends React.PureComponent {
  constructor(props) {
    super(props);
    // product_data = [ ['product name', product cost, {product inventory}] ]
    let data_list = ProductList.product_data.map((value, index) => {
      // 生成每个item的属性
      return {
        // 静态属性
        image_src: this._getImageUrl(String(value[0])), // 图片地址
        product_cost: value[1],                         // 花费
        product_name: value[0],                         // 商品名字  
        inventory: value[2] ? value[2] : Number.MAX_SAFE_INTEGER, // 商品库存
        index: index,           //  商品在Shop列表的下标
        // 动态属性
        enable_buy: true,       //  是否可以买
        enable_sell: false,     //  是否可以卖
        buy_count: 0,           //  买了几个
      };
    });
    this.state = {
      column_count: 3,
      data_list: data_list,
      current_money: 100000000000,
    };
  }
}
  • MoneyBar
  1. 使用position: sticky; z-index: 9999;来实现附着效果.
  2. Shop.current_money绑定到react-animated-number来展示动态变化的剩余金钱
  3. formatMoney 工具函数将数字转化为英文表示法
  • ProductList
  1. 继续使用Grid布局, 通过Shop.data_list生成每个ProductCell
  2. 由于商品是固定且有限的,将ProductCell定义为stateless的组件, 购买和出售绑定到Shop处理, 并动态计算是否可以继续出售和购买(出售可能导致其他商品可以购买,购买可能导致购买其他商品的金额不足).
  • Receipt

遍历Shop.data_list[i].buy_count, 生产购买单项和总价即可.

最终实现效果
代码库

Summary

  1. React分函数组件和类组件, 函数组件返回值就是渲染的html元素, 类组件使用render函数表达需要渲染的html函数, 它们都接受props参数, 是由父节点在html上绑定传递过来的.
  2. html元素中使用{}执行js逻辑
  3. 函数组件可使用hooks, useState(val):产生/设置内部参数. 自定义hook可以方便添加公有属性, hook也可为函数组件添加生命周期逻辑
  4. 类组件要使用类似自定义hook的效果要利用HOC(高阶组件,以参数为组件,返回值为新组件的函数).
  5. 类组件在构造函数声明state,使用setState更新状态, 是否要更新html元素及更新的时机由react决定.
  6. 组件之间的数据流动, 简单办法可以使用传回调函数做参数.
  7. 条件渲染: if表达式或 flag && element
  8. 列表渲染: 对数组应用map函数, 每个生成的组件都应该有在列表内唯一的key, 且不能为数组下标, react通过key来决定列表元素是否发生了变化.(这个列表是只对ul/li生效还是所有元素组成的列表都生效存疑)
posted @ 2021-10-13 16:57  新新人類  阅读(58)  评论(0编辑  收藏  举报