zoukankan      html  css  js  c++  java
  • react实战与总结1

    Create React App 是用 React 创建新的单页应用的最佳方式。

      单页面应用(single-page application),是一个应用程序,它可以加载单个 HTML 页面,以及运行应用程序所需的所有必要资源(例如 JavaScript 和 CSS)。与页面或后续页面的任何交互,都不再需要往返 server 加载资源,即页面不会重新加载。你可以使用 React 来构建单页应用程序,但不是必须如此。React 还可用于增强现有网站的小部分,使其增加额外交互。用 React 编写的代码,可以与服务器端渲染的标记(例如 PHP)或其他客户端库和平共处

    参考:https://react.docschina.org/docs/create-a-new-react-app.html#create-react-app

    1、路由

    参考:https://create-react-app.dev/docs/adding-a-router

    https://reacttraining.com/react-router/web/guides/quick-start

    2、环境变量

    参考:https://create-react-app.dev/docs/adding-custom-environment-variables

    示例如下:

    .env.development文件
    REACT_APP_BASE_API = /v1

    3、开发版请求代理

    参考:https://create-react-app.dev/docs/proxying-api-requests-in-development

    https://segmentfault.com/q/1010000016754248/

    如果proxy的值是字符串,可以在package.json里添加proxy字段,例如:

    "proxy": "http://localhost:4000"

    如果proxy的值是一个json,则需要做如下修改:cnpm i http-proxy-middleware --save-dev;src文件夹根目录下创建 setupProxy.js 文件编辑proxy代码,例如

    const proxy = require('http-proxy-middleware');
    module.exports = function(app) {
      app.use([process.env.REACT_APP_BASE_API], proxy({ target: 'http://localhost:5000', changeOrigin: true }));
    };

    4、react-app-rewired

    参考:https://github.com/timarney/react-app-rewired/blob/master/README_zh.md

    https://github.com/arackaf/customize-cra

    此工具可以在不 'eject' 也不创建额外 react-scripts 的情况下修改 create-react-app 内置的 webpack 配置,然后你将拥有 create-react-app 的一切特性,且可以根据你的需要去配置 webpack 的 plugins, loaders 等。

    customize-cra提供了一组用于自定义利用react-app-rewired核心功能的Create React App v2配置,可以通过config-overrides.js文件来对webpack配置进行扩展。

    4.1)自定义webpack配置如resolve.alias【创建 import 或 require 的别名,来确保模块引入变得更简单】

    // config-overrides.js
    const { override, addWebpackAlias } = require('customize-cra');
    const path = require('path');
    module.exports = override(
      // 配置路径别名
      addWebpackAlias({
        pages: path.resolve(__dirname, 'src/pages'),
        utils: path.resolve(__dirname, 'src/utils'),
        assets: path.resolve(__dirname, 'src/assets')
      })
    )

    4.2)使用 antd-mobile 进行web开发【antd-mobile 是 Ant Design 的移动规范的 React 实现;antd 是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品

    参考:https://mobile.ant.design/docs/react/use-with-create-react-app-cn

    安装:npm install antd-mobile --save

    按需加载:使用 babel-plugin-import【用于按需加载组件代码和样式的 babel 插件】

    按需加载原理参考:https://ant.design/docs/react/getting-started-cn#按需加载

    // config-overrides.js
    const { override, fixBabelImports } = require('customize-cra');
    const path = require('path');
    module.exports = override(
      fixBabelImports('import', { libraryName: 'antd-mobile', style: 'css' })
    )

     然后只需从 antd-mobile 引入模块即可,无需单独引入样式,babel-plugin-import 会帮助你加载 JS 和 CSS

    其它问题

    1)postcss autoprefixer不生效

    解决方法:修改package.json的browserslist属性

    // 修改前
    "browserslist": {
      "development": [
        "last 1 chrome version",
        "last 1 firefox version",
        "last 1 safari version"
      ]
    }
    // 修改后
    "browserslist": {
      "development": [
        "> 1%",
        "last 2 versions"
      ]
    }

    2)样式冲突

    参考: https://create-react-app.dev/docs/adding-a-css-modules-stylesheet

    css模块化文件命名规则为[name].module.css 或 [name].module.scss 或 [name].module.sass,它允许你在不同的文件中使用相同的css类名而不用担心命名冲突【会自动生成唯一的类名,格式为[filename]\_[classname]\_\_[hash]】

    import React, { Component } from 'react';
    import styles from './style.module.scss';
    
    class PrdDetail extends Component {
      render() {
        return (
          <div className={styles["detail-container"]}>
            <div className={styles.left}></div>
          </div>
        );
      }
    }

    浏览器渲染:

     个人感觉使用起来很麻烦

    import React, { Component } from 'react';
    import styles from './style.module.scss';
    class OrderConfirm extends Component {
      render() {
        return (
          <div className={`clearfix ${styles['order-container']}`}>
            <p className={`${styles['basic-info-row']} ${styles['sum-info-row']}`}>共计 1 件商品,合计总额:<span className={`${styles.amount}`}>&yen;100</span></p>
          </div>
        );
      }
    }
    export default OrderConfirm;

    style.module.scss

    .order-container {
      color: blue;
    }
    .basic-info-row {
      height: 1.1rem;
      line-height: 1.1rem;
    }
    .sum-info-row {
      font-size: 0.3rem;
      .amount {
        color: lightblue;
      }
    }

    浏览器渲染结果:

    3) CSS in JS

    参考:http://www.ruanyifeng.com/blog/2017/04/css_in_js.html?utm_source=tuicool&utm_medium=referral

    以前,网页开发有一个原则,叫做"关注点分离"。简单说,就是一句话,不要写"行内样式"和"行内脚本"。React 出现以后,这个原则不再适用了。因为,React 是组件结构,强制要求把 HTML、CSS、JavaScript 写在一起。随着 React 的走红和组件模式深入人心,这种"关注点混合"的新写法逐渐成为主流

    const style = {
      'color': 'red',
      'fontSize': '46px'
    };
    
    ReactDOM.render(
      <h1 style={style}>
         Hello, world!
      </h1>,
      document.getElementById('example')
    );

    上面代码中,CSS 的font-size属性要写成fontSize,这是 JavaScript 操作 CSS 属性的约定。

    4)react的Fragment

     React 中的一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点

    render() {
      return (
        <React.Fragment>
          <ChildA />
          <ChildB />
          <ChildC />
        </React.Fragment>
      );
    }

    react

    • JSX,是一个 JavaScript 的语法扩展。

    我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离。

    在属性中嵌入 JavaScript 表达式时,不要在大括号外面加上引号。你应该仅使用引号(对于字符串值)或大括号(对于表达式)中的一个,对于同一属性不能同时使用这两种符号

    因为 JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。例如,JSX 里的 class 变成了 className,而 tabindex 则变为 tabIndex

    React 只更新它需要更新的部分:React DOM 会将元素和它的子元素与它们之前的状态进行比较,并只会进行必要的更新来使 DOM 达到预期的状态。

    为了便于阅读,我们会将 JSX 拆分为多行。同时,我们建议将内容包裹在括号中,虽然这样做不是强制要求的,但是这可以避免遇到自动插入分号陷阱。

    • 受控组件

    在 HTML 中,表单元素(如<input>、 <textarea> 和 <select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。对于受控组件来说,每个 state 突变都有一个相关的处理函数。

    class Login extends Component {
      constructor(props) {
        super(props);
        this.state = {
          codeBtnText: '获取验证码',
          phone: ''
        }
      }
    
      phoneChange(e) {
        this.setState({ phone: e.target.value })
      }
      sendPhoneCode() {
        console.log(this.state.phone)
      }
      render() {
        return (
          <div className="login-box">
            <div className="input-row">
              <input type="tel" className="phone-input" maxLength="11" placeholder="请输入手机号" value={this.state.phone} onChange={this.phoneChange.bind(this)} />
            </div>
            <div className="input-row code-row">
              <input type="text" className="code-input" maxLength="6" placeholder="请输入短信验证码" value={this.state.phoneCode} />
              <input type="button" className="code-btn" value={this.state.codeBtnText} onClick={this.sendPhoneCode.bind(this)} />
            </div>
          </div>
        );
      }
    }
    •  列表&key

    参考:https://react.docschina.org/docs/lists-and-keys.html

    https://es6.ruanyifeng.com/#docs/class#实例属性的新写法

    使用 Javascript 中的 map() 方法来遍历 numbers 数组。【类的实例属性除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层。】

    class Index extends Component {
      state = {navs: []}
      componentDidMount() {
        request({ url: 'group/groupContentList/zysrf_index_nav' }).then(response => {
          this.setState({navs: response.data})
        })
      }
      render() {
        const imgPrefix = process.env.REACT_APP_IMG_PREFIX
        return (
          <div className="index-container">
            <div className="nav-box clearfix">
              {this.state.navs.map(nav => (
                <div className="nav-item" key={nav.id}>
                  <img src={imgPrefix + nav.img_url} alt=""/>
                  <p>{nav.title}</p>
                </div>
              ))}
            </div>
          </div>
        );
      }
    }

      key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据 id 来作为元素的 key。当元素没有确定 id 的时候,万不得已你可以使用元素索引 index 作为 key。如果列表项目的顺序可能会变化,我们不建议使用索引来用作 key 值,因为这样做会导致性能变差,还可能引起组件状态的问题。如果你选择不指定显式的 key 值,那么 React 将默认使用索引用作为列表项目的 key 值。

    • 组合

    参考:https://react.docschina.org/docs/composition-vs-inheritance.html

    有些组件无法提前知晓它们子组件的具体内容。在 Sidebar(侧边栏)和 Dialog(对话框)等展现通用容器(box)的组件中特别容易遇到这种情况。我们建议这些组件使用一个特殊的 children prop 来将他们的子组件传递到渲染结果中

    • 条件渲染

    React 中的条件渲染和 JavaScript 中的一样,使用 JavaScript 运算符 if 或者条件运算符去创建元素来表现当前的状态,然后让 React 根据它们来更新 UI。你可以使用变量来储存元素,它可以帮助你有条件地渲染组件的一部分,而其他的渲染部分并不会因此而改变

     JSX 中内联条件渲染的方法:

    1)与运算符 &&

    通过花括号包裹代码,你可以在 JSX 中嵌入任何表达式。这也包括 JavaScript 中的逻辑与 (&&) 运算符。它可以很方便地进行元素的条件渲染。

    function Mailbox(props) {
      const unreadMessages = props.unreadMessages;
      return (
        <div>
          <h1>Hello!</h1>
          {unreadMessages.length > 0 &&
            <h2>
              You have {unreadMessages.length} unread messages.
            </h2>
          }
    </div>
      );
    }
    
    const messages = ['React', 'Re: React', 'Re:Re: React'];
    ReactDOM.render(
      <Mailbox unreadMessages={messages} />,
      document.getElementById('root')
    );

    在 JavaScript 中,true && expression 总是会返回 expression, 而 false && expression 总是会返回 false。因此,如果条件是 true&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它

     2)三目运算符

     另一种内联条件渲染的方法是使用 JavaScript 中的三目运算符 condition ? true : false

    render() {
      const isLoggedIn = this.state.isLoggedIn;
      return (
        <div>
          The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
        </div>
      );
    }
    • 组件 & Props & State
    // 函数组件
    function Welcome(props) {
      return <h1>Hello, {props.name}</h1>;
    }
    // class组件
    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    // 渲染组件
    const element = <Welcome name="Sara" />;
    ReactDOM.render(
      element,
      document.getElementById('root')
    );

    Props 的只读性:组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props。

    应用程序的 UI 是动态的,并会伴随着时间的推移而变化。在不违反props规则的情况下,state 允许 React 组件随用户操作、网络响应或者其他变化而动态更改输出内容

    •  状态提升

      在 React 中,将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的“状态提升”。在 React 应用中,任何可变数据应当只有一个相对应的唯一“数据源”。通常,state 都是首先添加到需要渲染数据的组件中去。然后,如果其他组件也需要这个 state,那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state。 

    •  基于路由的代码分割

    参考:https://zh-hans.reactjs.org/docs/code-splitting.html

      打包是个非常棒的技术,但随着你的应用增长,你的代码包也将随之增长。尤其是在整合了体积巨大的第三方库的情况下。你需要关注你代码包中所包含的代码,以避免因体积过大而导致加载时间过长。为了避免搞出大体积的代码包,在前期就思考该问题并对代码包进行分割是个不错的选择。 代码分割是由诸如 Webpack,Rollup 和 Browserify(factor-bundle)这类打包器支持的一项技术,能够创建多个包并在运行时动态加载。对你的应用进行代码分割能够帮助你“懒加载”当前用户所需要的内容,能够显著地提高你的应用性能。尽管并没有减少应用整体的代码体积,但你可以避免加载用户永远不需要的代码,并在初始加载的时候减少所需加载的代码量

    在你的应用中引入代码分割的最佳方式是通过动态 import() 语法React.lazy 函数能让你像渲染常规组件一样处理动态引入(的组件),然后应在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)。

    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    import React, { Suspense, lazy } from 'react';
    const Home = lazy(() => import('./routes/Home'));
    const About = lazy(() => import('./routes/About'));
    
    const App = () => (
      <Router>
        <Suspense fallback={<div>Loading...</div>}>
          <Switch>
            <Route exact path="/" component={Home}/>
            <Route path="/about" component={About}/>
          </Switch>
        </Suspense>
      </Router>
    );

    react-router4+

    • 路由传参

    参考:https://reacttraining.com/react-router/web/api/Route/route-props

    import React from "react";
    import ReactDOM from "react-dom";
    import { BrowserRouter as Router, Route } from "react-router-dom";
    
    // All route props (match, location and history) are available to User
    function User(props) {
      return <h1>Hello {props.match.params.username}!</h1>;
    }
    
    ReactDOM.render(
      <Router>
        <Route path="/user/:username" component={User} />
      </Router>,
      node
    );

     路由传参(参数不显示在地址栏)

    参考:https://www.jianshu.com/p/6f7b5d37f3bc(验证query传的参数同样不显示在地址栏)

    https://reacttraining.com/react-router/web/api/history

    https://reacttraining.com/react-router/web/api/withRouter

    React 中正常来说只有在 <Route> 包裹的组件中才能在 this.props 属性中找到 history 对象,但有些情况下我们就是希望在一个没被 <Route> 包裹的组件中用到 history 对象。解决方案:withRouter
    import React, { Component } from 'react';
    import { withRouter } from "react-router";
    
    class BuyPop extends Component {
      goOrderConfirm() {
        const prdDetail = prdData.product
        const prdInfo = {
          id: prdDetail.id,
          selectedPackage: selectedPackage
        }
        // this.props.history.push({pathname: '/orderConfirm', state: prdInfo})
        this.props.history.push('/orderConfirm', prdInfo)
      }
      render() {
        return (
          <div className="buy-pop">
              <div className="next-btn orange-btn" onClick={this.goOrderConfirm.bind(this)}>下一步</div>
            </div>
          </div>
        )
      }
    }
    BuyPop = withRouter(BuyPop)
    
    class PrdDetail extends Component {
      // ...
      render() {
        return (
          <div className="detail-container">
            {this.state.buyPopFlag && <BuyPop close={this.closeBuyPop.bind(this)} />}
          </div>
        );
      }
    }

     orderConfirm页面接收参数:this.props.location.state

  • 相关阅读:
    selenium之WebDriver API
    python开发之面试题
    python开发之协程
    Python爬虫
    Python基础
    Django-搭建win7虚拟环境-virtualenv
    Linux系列
    Python知识点
    Python知识点
    Python基础-生物信息:找出基因,生物学家使用字母A、C、T和G构成的字符串建模一个基因组。
  • 原文地址:https://www.cnblogs.com/colorful-coco/p/11948892.html
Copyright © 2011-2022 走看看