React学习笔记

2020-07-20  本文已影响0人  zyghhhh

jsx语法

  1. 遇到{ } 就把里面的代码当js解析
  2. 遇到< > 就把里面的代码当html解析

声明组件

  1. 组件使用class声明函数组件,并且暴露出去
  2. 组件首字母必须大写(否则会报错)
  3. 声明组件使用React.Component方法
  4. 组件内部一定要有render(){}
  5. render()内部写 return ()
  6. 组件只能渲染一个根节点标签,就是所有的html要用一个标签包裹着

this指向问题

  1. react内置的方法this指向实例对象,比如state render
  2. 自定义的方法this为undinfied,但是写在组件内部,可以用箭头函数,this就会指向组件了,组件this是实例对象

三大对象

  1. state: 定义初始化数据,组件内部可以通过this.state.xx拿到
  2. props:可以父组件拿到传递过来数据,通过this.props.xx拿到
  3. ref:

组件间传值

react-router

  1. 下包 npx react-router-dom
  2. 引入
 
  1. 使用
  2. 说明
  1. 参数

生命周期

setState

条件渲染

  1. 定义数据状态
  2. 根据数据状态的不同来决定渲染什么代码
  3. 要配合jsx语法写

列表渲染

  1. 在jsx语法{ }中直接使用js的方法遍历生产html标签

key的作用

表单

请求交互

跨域处理

redux & react-redux

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App/>
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

第三方中间件

合并reducer和合并action

1 // 把actions都引入到一起
import * as countActions from './store/actions'

2 // 传入actions 和disapatch  但只有当actions是方法的时候 才会成为counter的属性
const mapDispatchToProps = (dispatch) => {
  return {
    counter:bindActionCreators(countActions,dispatch)
  }
}

3 //调用  
this.props.counter.xxx()

1// 取出这个方法
import {combineReducers} from 'redux'

2// 把所有的reducer都引入到index.js中,因为要在这里生成store 通过provider传给组件
import {count,user} from './store/reducers'

3// 合并reducers创建
//合并reducer 为一个对象 然后整体暴露出去
export const reducers = combineReducers({
  count,
  user
})

4// 创建store
const store = createStore(reducers)

5// 读取数据
 读取数据时需要需要state.xxx  因为合并的时候相当于把数据都包装到一个对象中了
const mapStateToProps = (state) => {
  return {
    count:state.count,
    user:state.user
  }
}

调试

chrome
1 安装依赖 安装插件
chrome插件 redux-devtool
依赖 redux-devtools-extension

首屏优化之组件&路由懒加载

hook

useState: 用来创建状态和改变状态的方法

/*
count值为10
setCount是改变count的方法,不再用setState去改变状态
*/
//创建简单数据类型数据
const [count,setCount] = useState(10)
//创建复杂数据类型数据
const [obj,setObj] = useState({
  name:'小米',
  age:18
})

useEffect: 相当于类组件中的什么周期,

它代替了componentDidMount,componentDidUpdate,componentWillUnmount
也就是说可以在这个方法中做 发请求,监听更改数据后变化重新渲染,和解绑dom事件,清除定时器,和清除网络状态

componentDidMount: 初始化发请求
componentDidUpdate: 数据变化后重新渲染操作监听
componentWillUnmount: 解绑dom事件,清除定时器,和清除网络状态(这些操作我的另一篇文章中又提起 

react中componentWillUnmount中可以做的事:https://www.jianshu.com/p/ea3cfc0a85da

useEffect 写法

//1 useEffect中要写一个回调函数
//2 可以写多个useEffect方法  每一个中做每一个生命周期中做的事以此来区分业务逻辑
useEffect(() => {
//如果直接这样写 会一直执行  页面初始化和数据更新重新渲染时都会调用这个方法
})

useEffect(() => {

  //如果第二个参数传入一个数组这样写,这个方法就是componentDidMount,在页面渲染完后执行
  //第二个参数是一个数组,当数组的每一项都没有发生变化,useEffect就不会重复执行,所以如果只想页面初始化调用一次的话就传一个空数组
  //可以在这里面绑定一些dom事件  比如 window.addEventLister('resize',callback,boolean)
  window.addEventLister('resize',callback,boolean)
  
  //开启定时器
  var time = setInterval(() => {},1000)


// 如果retrun一个函数的话 这个函数的作用就是页面卸载前触发的,相当于componentWillUnmount
// 可以做一些收尾工作,比如解绑dom事件,清除定时器  
return () => {
  //解绑Dom
 window.removeEventLister('resize',callback,boolean)
  
  //清除定时器
  clearInterval(time)
}
},[])

// 3 副作用
useEffect(() => {
    //mount后绑定的dom时间 如果该dom会被替换或者删除 绑定的事件就会失效,所以我们不能只再mount后绑定一次,要重复绑定和解绑
    document.getElementById('size').addEventListener('click',Click,false)
    return () => {
    document.getElementById('size').removeEventListener('click',Click,false)
      
    }
  })


useMemo: 用传入的数组来判断函数是否从新执行计算

-用来性能优化,传入一个数组,数组中数据变化或为true的时候执行,在渲染过程中调用,有返回值可以参与后面逻辑渲染,有点类似vue计算属性。

import React, { useState, useMemo } from 'react'
 
const Counter = (props) => {

  return (
    <div>
      //父组件传子组件 入参接受 子组件使用
      {props.count}
    </div>
  )
}


const App = () => {
  const [count, setCount] = useState(0)

  // 两个参数 第一个参数是要执行的功能函数, 第二个参数[] 只传空数组就只执行一次
  // useMemo 在渲染期间完成 而且有返回值 返回值可以参与渲染的,用法和useEffect一样 
  let double = useMemo(() => { 
    console.log('useMemo')
    return count * 2 
  }, [count === 3])

  return (
    <div>
      <button
        onClick={() => {
          setCount(count + 1)
        }}
      >
        click({count}) ,double:({double})
      </button>
      <Counter count={count} />
      <hr />
    </div>
  )
}

export default App

useCallback

 useMemo(() => fn)
 useCallback(fn)
如果useMemo返回的是一个回到函数,使用useCallBack就可以省略掉外层包裹函数

useCallback 小例子 附说明

import React, { useCallback,useState } from 'react';

const CB = () => {
  const [count,setCount] = useState(0)
  const [count1,setCount1] = useState(0)

  /**
   * useCallback 传两个参数
   * 1 回调函数
   * 2 数组  数组中是另一个值  用来决定让不让第一个值的那个回调函数执行
   * 3 如果 第二个参数中的值发生了变化则允许第一个参数执行,否则不允许第一个参数执行
   * 4 这样可以避免一些不必要的执行 达到性能优化
   * 
   * 
   * 当第一次执行useCallback中第一个参数这个回调时,不会受第二个参数影响,
   * 但之后的每一次触发都先去判断第二个参数中的值有没有发生变化,如果有就让第一个参数执行,
   * 如果没有就不让第一个参数执行
   */

  return(
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count +1)}>click me</button>
      <p>{count1}</p>
      <button onClick={useCallback(() => setCount1(count1 +1),[count])}>click me</button>
    </div>
  )
} 

export default CB
import React, { useState, createContext, useContext } from 'react'
//第一步创建context实例
const MyContext = createContext()

//父组件
const Context = () => {
  const count = useState(22)


  return (
    <div>
      <h2>这里是context测试</h2>
      <!--2 使用实例标签包裹子组件 并传入数据-->
      <MyContext.Provider value={count}>
        <Child ></Child>

      </MyContext.Provider>

    </div>
  )
}

<!--子组件-->
const Child = () => {
  <!-- 3 使用useContext() 获取传入的状态 --> 
  const [state, dispatch] = useContext(MyContext)
  console.log(state)
  return (
    <div>
      {state}
    </div>
  )

}

useContext + useReducer 实现数据共享

  
import React, { useState, createContext, useContext, useReducer } from 'react'

/**
 * 核心思想:
 *  通过 createContext创建的context对象包裹子组件,并把用useReducer创建出来的dispatch传递
 *  给子组件树。在子组件中分发action触发reducer状态机函数改变数据。
 * 
 */
const initstate = 0

const reducer = (state, action) => {
  console.log(state)
  console.log(action)
  switch (action.type) {
    case 'add':
      return state + 1
    case 'reduce':
      return state - 1
    case 'add5':
      return state + action.data
    case 'reduce5':
      return state - action.data
    default:
      return state
  }
}

// 1 创建context对象
const MyContext = createContext(null)

//子组件
const Child = (props) => {
  let dispatch = useContext(MyContext)

  return (
    <div>
      <h2>
        {props.count}

        {/* state */}
        <div>
          <button
            onClick={() => {
              dispatch({

                type: 'add'
              })
            }}
          >+</button>
        </div>
        <div>
          <button
            onClick={() => {
              //携带参数的aciton 
              dispatch({
                data: 5,
                type: 'add5'
              })
            }}
          >+5</button>
        </div>
        <div>

          <button
            onClick={() => {
              dispatch({
                type: 'reduce'
              })
            }}
          >-</button>
        </div>
        <div>

          <button
            onClick={() => {
              //携带参数的aciton 
              dispatch({
                data: 5,
                type: 'reduce5'
              })
            }}
          >-5</button>
        </div>
      </h2>
    </div>
  )
}

// 父组件
export default () => {

  const [state, dispatch] = useReducer(reducer, initstate)
  return (
    <div>
      hello word
      {/* 父组件用context对象标签 包裹子组件树 并把dispatch传递给子组件 子组件中去分发action触发reducetion 改变数据 */}
      <MyContext.Provider value={dispatch}>
        <Child count={state} />
      </MyContext.Provider>
    </div>
  )
}


自定义hook

1.定义一个函数,可以使用hook的提供的api,return直接返回一个可用的数据 在主组件中使用。可以把重复的逻辑提取到这个hook中。这个hook中执行逻辑返回状态。组件中直接使用就好了。比如发请求什么的。把url和data传进去。返回出请求结果。等等操作
2.名字必须是use开头

import React,{useState,useEffect} from 'react';


const useMousePosition = () => {
  const [positions,setPositions] = useState({x:0,y:0})

  useEffect(() => {

    const updateMouse = (e:MouseEvent) => {
      console.log('inner');
      setPositions({x:e.clientX,y:e.clientY})
    }
    document.addEventListener('mousemove',updateMouse)

    return () => {
      document.removeEventListener('mousemove',updateMouse)
    }

  })

  return positions
}


export default useMousePosition


上一篇 下一篇

猜你喜欢

热点阅读