react 初学

150 阅读7分钟
1、安装
    npm init -y // 初始化npm管理工具->生成package.json文件
    npm i react react-dom //安装react
    //npx是npm内置的一个命令,脚手架创建项目
    npx create-react-app my-app

2、简单实用:
 const title = React.createElement('h1', null, 'Hello React') 
 ReactDOM.render(title,document.getElementById('root'))
 //jsx
 const jsx = (<div className="app"><h1>Hello React! 动态变化数据:{count}</h1> </div>)
 
 //JSX是React.createElement方法的语法糖**
 //React元素的有些属性名使用小驼峰命名法
-   如果要渲染一组数据,应该使用数组的 map() 方法
-   注意:渲染列表时应该添加 key 属性,key 属性的值要保证唯一
-   原则:map() 遍历谁,就给谁添加 key 属性
-   注意:尽量避免使用索引号作为 key !

style属性{{属性:值}}
<h1 style={{ color: 'red', backgroundColor: '#eee' }}> 
  JSX的样式处理 
</h1>
属性名小驼峰命名
<h1 className="title"> 
 JSX的样式处理 
</h1> 
3、 创建组件
    //函数创建组件
    import React from 'react';
    function Hello() { 
      return ( 
        <div>这是我的第一个函数组件!</div> 
      ) 
    } 
    ReactDOM.render(<Hello />, root) 
    // 类组件
    import React from 'react';
    class Hello extends React.Component { 
      render() { 
        return <div>Hello Class Component!</div> 
      } 
    } 
    ReactDOM.render(<Hello />, root) 

4、 事件绑定 this问题,e
    -   语法:on+事件名称={事件处理程序fn},比如:onClick={() => {}}
    function handleClick(e) { 
      e.preventDefault() 
      console.log('事件对象', e) 
    } 
    <a href="http://www.baidu.com" onClick={handleClick}>点我,不会跳转页面</a> 
    //this 指向
    //利用bind修改this指向组件实例
    //利用箭头函数(推荐)


5、有状态组件和无状态组件的区别
    -   函数组件又叫做无状态组件,类组件又叫做有状态组件
    -   状态(state)即数据,某个时刻的值
    -   类组件有自己的状态,负责更新 UI,让页面“动” 起来 (响应式)
    -   函数组件没有自己的状态,只负责数据展示(静)

    // 类组件中的state 和 setState
    -   状态(state)即数据,是组件内部的私有数据,只能在组件内部使用
    -   state 的值是**对象**,表示一个组件中可以有多个数据 相当于vue的data
    -   状态是可变的 this.setState({ key:val, key2:val2 })
    -   注意:不要直接修改 state 中的值,这是错误的!!! ->this.state.num=2这样写不可以!

    -   setState() 作用:
        -   修改 state
        -   更新UI
    -   思想:数据驱动视图

6、 表单
    // 受控组件 相当于vue 中的v-model 
    <input type="text" value={this.state.name} onChange={changeVale}>
    changeVale =(e) =>{
        this.setState({
            name: e.target.value;
        })
    }
    // 非受控组件
    -   说明:借助于 ref,使用原生 DOM 方式来获取表单元素值
    -   ref 的作用:获取 DOM 或组件实例
    1.  调用 React.createRef() 方法创建一个 ref 对象
        ```
        constructor() { 
            super() 
            this.txtRef = React.createRef() 
        } 
        ```
    2.  将创建好的 ref 对象添加到文本框中

      <input type="text" ref={this.txtRef} /> 

    3.  通过 ref 对象获取到文本框的值
      console.log(this.txtRef.current.value) 

    适用场景:
    -   操作DOM元素和类组件
        -   控制元素样式或媒体播放等
    注意
    -   不能在函数**组件上**使用ref,因为它没有实例。
    -   不要过度使用Refs7、 组件通讯
    -   组件是封闭的,要接收外部数据应该通过 props 来接收
    -   props的作用:接收传递给组件的数据
    -   传递数据:给组件标签添加属性
    -   接收数据:函数组件通过参数props接收数据,类组件通过 this.props 接收数据
    注意:使用类组件时,如果写了构造函数,应该将 props 传递给 super(),否则,无法在构造函数中获取到 props!
    function Hello(props){
        console.log(props.name);
    }
    <Hello name="java"  />
    class Hello extends React.Component{
        render(){
            console.log(this.props.age);
        }
    }
    <Hello  age={19} />

    父传子,子组件通过props里接收父组件传值
    <child name={this.state.name} />
    子传父, 子组件调用通过父组件传递过来的方法,改变父组件中的值
    子组件:this.props.getMsg("msg");
    父组件:<Child getMsg={this.getChildMsg} />
            getChildMsg(msg) =>{ console.log(msg)}
    兄弟组件
    -   将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
    -   思想:**状态提升** : 父->子A和子B-> 把A和B共同的state放到父组件中维护
    -   公共父组件职责:1. 提供共享状态 2. 提供操作共享状态的方法
    -   要通讯的子组件只需通过 props 接收状态或操作状态的方法

    亲戚组件:context
    作用:Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
    1.  调用 React. createContext() 创建 Provider(提供数据) 和 Consumer(消费数据) 两个组件。
      const { Provider, Consumer } = React.createContext() 

      <Provider value="pink"> 
        <div className="App"> 
          <Child1 /> 
        </div> 
      </Provider> 

    2.  使用 Provider 组件作为父节点。设置 value 属性,表示要传递的数据。
    3.  调用 Consumer 组件接收数据
        <Consumer>{data => <span>data参数表示接收到的数据:{data}</span>}</Consumer> 

8、props深入
    1、children属性
    children 属性:表示组件标签的子节点。当组件标签有子节点时,props 就会有该属性,
    children 属性与普通的props一样,值可以是任意值(文本、React元素、组件,甚至是函数
    <Child>大哭大哭大哭</Child> 
    console.log(this.props.children); // 大哭大哭大哭 
    2、props校验
        1)安装包 prop-types (npm i prop-types)
        2import PropTypes from 'prop-types'; 
        3function App(props) { 
          return (<h1>Hi, {props.colors}</h1>)
        } 
        // 类型定义
        App.propTypes = {   
          // 约定colors属性为array类型   
          // 如果类型不对,则报出明确错误,便于分析错误原因   
          colors: PropTypes.array 
        }
            注意:
        1.  常见类型:array、bool、func、number、object、string
        2.  React元素类型:element
        3.  必填项:isRequired
        4.  特定结构的对象:shape({ })
        // 常见类型 
        optionalFunc: PropTypes.func, 
        // 必选 
        requiredFunc: PropTypes.func.isRequired, 
        // 特定结构的对象 
        optionalObjectWithShape: PropTypes.shape({ 
          color: PropTypes.string, 
          fontSize: PropTypes.number  
        })

    3、props默认值
        // 设置默认值 
        App.defaultProps = { 
          pageSize: 10 
        } 
    
 9、react生命周期
 
![react生命周期.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8411fff2364049fb813b6fa3dd3a23ab~tplv-k3u1fbpfcp-watermark.image?)
更新时(更新阶段):执行时机:1. setState() 2. forceUpdate() 3. 组件接收到新的props/作为子组件

10、组件复用
    1、render props模式 2. 高阶组件(HOC1class Aa extends React.Component{
        state={ name: 'aa', age: 18}
        render(){
            this.props.render(this.state);
        }
    }
    <Aa render=((state)=>{console.log(state.name)}) />
    2、高阶组件
    const withHoc = (WrappedComponent) =>{
        return class extends React.Component{
                    state = {
              a:0
            }	

            add=()=> {
              this.setState({
                a: ++this.state.a
              })
            }

            render(){
                return (
                  <div>
                    // 参数是组件
                    <WrappedComponent a={this.state.a} fn={this.add} />    
                  </div>
                )
            }
        }
    }
    const eComponet = withHOC(WrappedComponent);
    
11、路由
    1、安装$ npm i react-router-dom 
    2、使用
        import { BrowserRouter as Router, Route, Link } from 'react-router-dom' 
    // 路由配置和导航
    <Router>
      <nav className="menu">
        <Link to="/home">home</Link>
      </nav>
      <div className="app">
        <Route path="/home" component={Home} />
      </div>
    </Router>
    **注意**:
    -   Router 组件:包裹整个应用,一个 React 应用只需要使用一次
    -   RouteLink组件:必须在Router 组件内部
    动态路由
        <Route path="/about/:id" component={About} />
       动态路由的参数获取:this.props.match.params
    编程式导航。。。
    class Login extends Component { 
      handleLogin = () => { 
        this.props.history.push('/home') 
      } 
      render() {...省略其他代码} 
    }
 12、高级
     1setState(stateChange[, callback])
     第二个参数可以获取stateChange后的值
     多次调用 setState() ,但是react会做批处理和覆盖,且只会触发一次重新渲染
     2setState((state, props)=>{}[, callback]) 
     这种多次调用setState,不会覆盖,会触发多次
     3、组件更新机制
        setState() 的两个作用: 1. 修改 state 2. 更新组件(UI)
        过程:父组件重新渲染时,也会重新渲染子组件。但只会渲染当前组件子树(当前组件及其所有子组件)
     4、只渲染根组件有关的数据轻量 state:**只存储跟组件渲染相关的数据**
     5、使用钩子函数 **shouldComponentUpdate(nextProps, nextState)**减少不必要的重新渲染
     6、纯组件 PureComponent: 纯组件内部通过分别 对比 前后两次 props 和 state 的值,来决定是否重新渲染组件
     7、虚拟 DOM:本质上就是一个 **JS 对象**,用来描述你希望在屏幕上看到的内容
         -   初次渲染时,React 会根据初始state(Model)结合jsx元素结构,创建一个虚拟 DOM 对象(树)。
-   根据虚拟 DOM 生成真正的 DOM,渲染到页面中。
-   当数据**变化后**(setState()),重新根据新的数据,**创建新的虚拟DOM对象**(树)。
-   与上一次得到的虚拟 DOM 对象,使用 **Diff 算法** 对比(找不同),得到需要更新的内容。
-   最终,React 只将变化的内容更新(**patch**)到 DOM 中,重新渲染到页面。
    8、diff
        1、元素类型:如果两棵树的根元素类型不同,React 会销毁旧树,创建新树
        2、元素属性:React 会对比两者的属性是否相同,只更新不同的属性
        3、当处理完这个 DOM 节点,React 就会递归处理子节点。
        4key:
            说明:key 属性在 React 内部使用,但不会传递给你的组件
            推荐:在遍历数据时,推荐在组件中使用 key 属性:`<li key={item.id}>{item.name}</li>`
    注意:**key 只需要保持与他的兄弟节点唯一即可,不需要全局唯一**
    注意:**尽可能的减少数组 index 作为 key,数组中插入元素的等操作时,会使得效率低下**

生命周期:

react生命周期.png

图片 1.png