• React笔记1


    1.react基础:类组件、函数式组件、ES5/ES6继承

    在创建一个vue项目的时候,
    
    1.在index.js文件中引入react模块,引入在需要的节点所需要的组件
    import React from 'react'; // 必须要引入的模块
    import ReactDOM from 'react-dom'; // 给某一个DOM节点渲染时用到,它是从react中分离出来的
    
    import App from '@/components/App'; // React的一个组件
    
    // 将虚拟的组件渲染到视图中
    // 组件名字必须是大写,如果是小写的话它会认为是html标签,组件的文件名也建议大写
    ReactDom.render ( // render是一个钩子函数
    	<APP />,
        document.getElementById('root') //表示的是组件放到哪个节点中
    )
    
    2.在components文件夹下,编写组件App.jsx
    import React from 'react'
    /**
    在react中开发组件模式:
     > ES6  class类写法   类组件  
     > ES6  箭头函数写法   函数式组件   ----无状态组件
    */
    // return()   ()内部的代码写的是虚拟Dom,符合jsx语法
    //class 类:
    class App extends React.Component {
        render () {
            return (
            <div>hello react</div>
            )
        }
    }
    export default App;
    
    // 函数式组件
    const App = () => {
        return (
        <div> hello function</div>
        )
    }
    
    
    如何选择类组件还是函数式组件?
       如果一个组件需要有状态,那么一定不要写函数式组件,函数式组件又会被成为 无状态组件,函数式组件一般会使用为UI组件(只负责渲染视图,数据都来源于父组件)---- 在react16.8的时候要注意一下(有另一种说法)
     
    
    • ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。
    • ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。

    子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。

    2.生命周期钩子函数

    React的生命周期的钩子函数

    挂载时 ---------- 初始化阶段
    • constructor() -------声明属性
    • componentWillMount() --------即将挂载组件
    • render() --------初次渲染数据
    • componentDidMount() ----------组件挂载完毕,可以在此处进行请求数据
    更新时 ---------运行时阶段
    • componenttWillReceiveProps(nextProps) --------将接收到组件的数据
    • shouldComponentUpdate() ------------- 当state或者props发生改变时,组件是否更新,默认更新,返回值为布尔类型
    • componentWillUpdate() ------------组件即将更新
    • render() -------------组件更新
    • componentDidUpdate() ----------------组件更新完毕,dom操作
    卸载时 ---------销毁阶段
    • componentWillUnmount() -------------组件销毁---定时器、计数器等
    错误处理
    • componentDidCatch() --------当react组件数出现错误时执行

    常用的react的生命周期钩子函数

    constructor() 通过给 this.state 赋值对象来初始化内部 state。为事件处理函数绑定实例

    render() 只要是组件就必须有的

    componentDidMount() 如果需要请求数据,如果需要DOM操作,实例化操作

    componentDidUpdate() 如果需要DOM操作,实例化操作

    componentWillUnmount() 如果需要清除定时器,计时器,实例对象

    3.什么是JSX

    jsx它既不是一个字符串也不是一个HTML,是javascript的语法拓展。jsx可以生成react中的元素,组件就是由元素组成的。
    jsx的特性属性,在属性中嵌入javascript代码时,在大括号外面不用加引号
    jsx可以防止javascript脚本攻击,因为在渲染的时候,它会先将代码转化成字符串。
    

    4.props和state有什么区别

    props是只读的,它用在组件与组件之间
    可以把props理解为从外部传入组件内部的数据。由于React是单向数据流,所以props基本上也就是从服父级组件向子组件传递的数据。
    state可读可写,它用在组件内
    它就是数据的状态
    
    1. state是组件自己管理数据,控制自己的状态,可变;
    2. props是外部传入的数据参数,不可变;
    3. 没有state的叫做无状态组件,有state的叫做有状态组件;
    4. 多用props,少用state。也就是多写无状态组件。

    5.路由配置

    项目目录树:入口找布局,布局找页面,页面找的是组件,组价中可以找子组件

    1. 在入口文件中配置路由

      import { BrowserRouter as Router, Switch, Route } from react-router-dom
      import App from '@/layout/App'
      import Detail from '@/layout/Detail'
      
      <Router>
          <Switch>
          	<Route path="/detail" component={ Detail } />
          	<Route path="/" component={ App } />
      	</Switch>
      </Router>
      
    2. 在布局文件中配置路由:带参数

      <Switch>
          <Route path="/detail/order" component={ Order }/>
          <Route path="/detail/:id" component={ Detail }/>
      </Switch>
      
    3. 在布局文件中配置路由:不带参数

      import Home from '@/view/Home'
      import Kind from '@/view/Kind'
      import Cart from '@/view/Cart'
      import User from '@/view/User'
      import { Route, Switch, NavLink, Redirect } from 'react-router-dom'
      
      <Switch>
            <Route path= '/home' component={ Home } />
            <Route path= '/kind' component={ Kind } />
            <Route path= '/cart' component={ Cart } />
            <Route path= '/user' component={ User } />
            <Redirect to ='/home' />   //重定向
      </Switch>
      
      <NavLink to="/home"><NavLink>  //点击跳转,如果有样式变化用NavLink
       //<Link to={ "/detail/id=" + item.id }><Link>  //没有样式变化的跳转,用Link
      

    注:路由的查找是从上到下的,所以path = "/"一定要放在最下面,否则就直接进入path = "/"页面,找不到path="/detail" 页面

    布局文件不写具体页面,子组件数据由页面传递,所以子组件中可以用函数式组件

    注:详情页跳转时path="/detail/:id"

    1. 重定向和404页面

      import NoMatch from '@/view/NoMatch';
      <Redirect exact from = '/' to ='/home' />  //exact表示只有“/”才能重定向到“/home”
         <Route component = { NoMatch } />
      

    6.自定义封住组件

    1.利用{...this.props}将父组件中的值传递到子组件中,在子组件中{ }使用

    2.结合类似vue的插槽完成自定中介部分的内容

    封装Header组件

    //<Header>组件
    import React from 'react'
    
    export default (props) => {
      console.log(props)
      const { left, right, content, onLeft, onRight } = props //从父组件中传过来的值
      return (
        <ul>
          <li onClick = { () => {
            if(props.match.path === '/home') {
              return 
            }
            props.history.goBack()
            // onLeft()
          }
          }>
            {left}
          </li>
          <li>{props.children? props.children : content? content : ''}</li>
          <li onClick = { () => {
            onRight()
          }}>{right}</li>
        </ul>
      ) 
    }
    
    
    //父组件中引用子组件的地方
    <Header
              left = "返回"
              content = "搜索"
              right = "扫一扫"
              onLeft = {() => {
                // this.props.history.goBack()
                console.log('返回')
              }}
              onRight = { () => {
                console.log('扫一扫')
              }}
              {...this.props}
              >
                <div className="seach">请输入搜索的内容</div>
              </Header>
    
    7.引入移动端react ant-design-mobile UI库‘’
    1. 安装 ant UI库文件

      cnpm i antd-mobile -S 
      
    2. 在index页面中引入文件(引入 Promise 的 fallback 支持 (部分安卓手机不支持 Promise))

      将此段代码直接替换
       <meta name="viewport" content="width=device-width, initial-scale=1" />
      替换为:
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
        <script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script>
        <script>
          if ('addEventListener' in document) {
            document.addEventListener('DOMContentLoaded', function() {
              FastClick.attach(document.body);
            }, false);
          }
          if(!window.Promise) {
            document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>');
          }
        </script>
      
    3. 在config/webpack.config.js中添加UI库的配置。(由于我们用到是react脚手架将config独立出来了,没有babel-plugin-文件)

      npm i babel-plugin-import -D
      
      在第357行,粘贴
      ["import", { libraryName: "antd-mobile", style: "css" }] // `style: true` 会加载 less 文件
      
    4. 基本配置完成,接下来需要哪个组件引入即可

    7.React 状态管理器

    1.Redux:(最基本的写法)

    ReduX并不独属于React,他是js的状态管理容器,在vue中也能用,只是在react中用起来更好,react-redux是属于react的

    在store.js页面中 -》 index.js页面引入store监听事件 -》在App页面disptch触发事件改变store中的值

    //在store->index.js文件中配置状态管理器
    import { creatStore } from 'redux';
    
    const reducer = (state = {
        bannerlist: [],
        prolist:[]
      },action) => {
        const { type, data } = action;
        switch (type) {
          case 'CHANGE_BANNER_LIST': return Object.assign({}, state, {bannerlist:data})
          case 'CHANGE_PRO_LIST': return Object.assign({}, state, { prolist: data })
          default:
            return state;
        }
      }
    
      const store = creatStore(reducer);
    
      export default store;
    
    //在index.js入口文件中监听状态管理器的变化
    import React from 'react'
    import ReactDOM from 'react-dom'
    
    import App from './App'
    import store from './store'
    
    function renderFn(){
      ReactDOM.render(
        <App />,
        document.getElementById('root')
      )
    }
    
    renderFn();
    
    //  如果检测到状态管理器中有变化触发
    store.subscribe(renderFn)
    
    //在需要使用状态管理器数据的页面中(App.jsx)请求数据,改变状态状态管理器中的数据
    import React, { Component } from 'react';
    import axios from 'axios';
    import store from './store'
    
    export default class extends Component {
      componentDidMount () {
        axios.get('https://www.daxunxun.com/banner').then(res => {
          console.log(res.data,'data');
          console.log(store,'store');
          store.dispatch({
            type: 'CHANGE_BANNER_LIST',
            data: res.data
          })
        })
        axios.get('https://www.daxunxun.com/douban').then(res => {
          store.dispatch({
            type: 'CHANGE_PRO_LIST',
            data: res.data
          })
        })
      }
      render () {
        console.log(store.getState(),'getState')
        const { bannerlist, prolist } = store.getState();
        return (
          <div>
            <h1>状态管理器</h1>
            <ul>
              {
                prolist.map(item => (
                  <li key = { item.id }>
                    { item.title }
                  </li>
                ))
              }
            </ul>
          </div>
        )
      }
    }
    
    2.redux + react-redux:(把一个组件拆分成了 容器组件 和 UI组件)

    容器组件只负责业务逻辑的处理,
    UI组件只负责数据的渲染

    将App.jsx文件拆分成App.jsx和UI.jsx,前者负责写业务逻辑,后者负责渲染数据

    //在index.js入口文件中改为
    ReactDOM.render(
      <Provider store = { store }>
        <App />
      </Provider>,
      document.getElementById('root')
    )
    
    //在App.jsx中写业务 逻辑
    import { connect } from 'react-redux'
    import axios from 'axios';
    import UI from './UI'
    
    // ui组件需要的状态
    const mapStateToProps = (state) => {
      return {
        bannerlist: state.bannerlist,
        prolist: state.prolist
      }
    }
    
    // ui组件的业务逻辑
    const mapDispatchToProps = (dispatch) => {
      return {
        getBannerlist () {
          axios.get('https://www.daxunxun.com/banner').then(res =>{
            dispatch({
              type: 'CHANGE_BANNER_LIST',
              data: res.data
            })
          })
        },
        getProlist () {
          axios.get('https://www.daxunxun.com/douban').then(res => {
            dispatch({
              type: 'CHANGE_BANNER_LIST',
              data: res.data
            })
          })
        }
      }
    }
    
    const App = connect(mapStateToProps, mapDispatchToProps)(UI)
    
    export default App;
    
    //在UI组件中渲染数据
    import React, { Component } from 'react';
    
    export default class extends Component {
      componentDidMount () {
        this.props.getBannerlist();
        this.props.getProlist();
      }
      render () {
        // console.log(store.getState(),'getState')
        const { bannerlist, prolist } = this.props;
        return (
          <div>
            <h1>状态管理器</h1>
            <ul>
              {
                prolist.map(item => (
                  <li key = { item.id }>
                    { item.title }
                  </li>
                ))
              }
            </ul>
          </div>
        )
      }
    }
    
    3.redux+ react-redux + react-thunk

    将状态管理器拆分到每个页面,然后在store->index文件中配置,单独创建一个action文件,将异步请求数据单拎出来。

    // action页面写异步请求
    import axios from 'axios';
    
    export default {
      getBannerlist (dispatch) {
        axios.get('https://www.daxunxun.com/banner').then(res => {
          dispatch({
            type: 'CHANGE_BANNER_LIST',
            data: res.data
          })
        })
      }
     }
    
    //状态管理器的入口文件
    import { createStore, combineReducers, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';
    import home from './home'
    import kind from './kind'
    
    const reducer = combineReducers({
      home,
      kind
    })
    // applyMiddleware 函数的作用就是对 store.dispatch 方法进行增强和改造,使得在发出 Action 和执行 Reducer 之间添加其他功能。
    //引入thunk插件后,我们可以在actionCreators内部编写逻辑,处理请求结果。而不只是单纯的返回一个action对象。
    const store = createStore(reducer, applyMiddleware(thunk));
    
    export default store;
    
    
    //状态管理器单个页面
    const reducer = (state = { 
      bannerlist: [],
      prolist: []
    }, action) => {
      const { type, data } = action;
      switch (type) {
        case 'CHANGE_BANNER_LIST': 
          return Object.assign({}, state, {bannerlist: data});
        case 'CHANGE_PRO_LIST':
          return Object.assign({}, state, {prolist: data});
        default:
          return state;
      }
    }
    
    export default reducer;
    

    8.利用脚手架创建一个React项目

    1.安装脚手架并且创建项目

    cnpm / npm i create-react-app -g
    create-react-app myapp

    使用npx直接创建项目

    npx是一种在npm中安装工具,也可以被单独的下载使用
    在npm 5.2.0 的时候发现会买一送一,自动安装了npx。

    npx create-react-app myapp
    (npm 的版本必须在5.2.0以上)

    2.修改配置文件、安装依赖

    运行 npm run eject 抽离配置文件

    修改package.json ,配置dev指令

    配置src文件夹的别名 @

    cnpm i node-sass -D
    cnpm i react-router-dom@4 redux react-redux redux-thunk axios antd-mobile -S

    在src下面创建main.scss在首页中引入

    3.配置入口文件index.js

    引入路由文件 import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';

    引入状态管理器文件 import store from './store';

    配置文件 import { Provider } from 'react-redux';

    全局引入组件库css文件 import 'antd-mobile/dist/antd-mobile.css';

    坑点:

    1.console.log()打印了2次内容

    如果在render中使用console.log,由于react的生命周期中,在其初始化阶段会执行一次render初次渲染,在运行时阶段执行一次render渲染数据,所以会执行2次,也就打印了2次。

    2.props提供的语法糖,可以将父组件中的所有属性复制给子组件。

    { ...this.props } 将父组件的路由信息传给组件。 this.props主要包含:history属性、location属性、match属性

    3.为啥写重定向和404页面在布局文件中?

    因为当我们输入网址的时候,它默认匹配“/”进入布局页面,如果你网址不对不算进入此项目,输入正确的地址后即进入项目,默认“/”进入布局页面,进入布局页面我们把它重定向到“/home”作为首页,如果输入其他匹配不到的就404页面。其他布局页面不用写,因为我们进入首页后,其他页面都是通过页面间跳转的,不需要手动在网址上输入。

  • 相关阅读:
    [React Testing] Create a Custom Render Function to Simplify Tests of Redux Components
    [React Testing] Test a Custom React Hook with React’s Act Utility and a Test Component
    Android之Android apk动态加载机制的研究
    Android之设备唯一识别
    ios之调用打电话,发短信,打开网址
    ios之如何读取plist
    android之卸载反馈的功能
    Android之针对webview的缓存
    Android之仿String的对象驻留
    Mac与Mac之中的共享方式
  • 原文地址:https://www.cnblogs.com/jtjianfeng/p/11356821.html
Copyright © 2020-2023  润新知