React@17+react-router@6+react-redux@7

1.React优势

jsx语法(必须用babel转译)、单向数据流、虚拟dom、声明式设计 、组件化开发、官方说是UI库

2.State和props的异同

相同点:

都是js对象

都是保存信息的

都能触发渲染

区别:

props是父组件传入,state是自己组件内创建管理的。

props在子组件不可修改,state可以在组件内部修改。

3.react事件机制

为了解决跨浏览器兼容性问题, React 会将浏览器原生事件 ( Browser
Native Event ) 封装为合成事件 ( SyntheticEvent ) 传⼊设置的事件处理
器中 。这里的合成事件提供了与原生事件相同的接⼝,不过它们屏蔽了底层浏
览器的细节差异,保证了⾏为的⼀致性 。

在react的dom中绑定事件不是在原dom上绑定,太浪费性能。而是通过事件代理给根标签(#root)。

4.类组件的生命周期

创建阶段:

1. construct:实力过程中自动调用该方法,在方法内部通过super关键字 获取父组件的props,通常初始化state或在this上挂载方法。

2. getDerivedStateFromProps:组件创建和更新阶段,不论是props还是state更新都会执行,第一个参数为即将更新的props,第二个参数为上一个状态的state,可以通过比较两者加限制条件防止无用的state更新(返回null就是不对state进行操作,也可以返回新的state)。

3. render:类组件必须实现的方法,用于渲染dom结构,可以访问组件的state和props。不要再render中setState,否则会出发死循环更新组件导致内存崩溃。

4. componentDidMount:组件挂载到真实dom节点后执行,多用于异步获取数据,监听等。

更新阶段:

1. getDerivedStateFromProps

2. shouldComponentUpdate: 用于告知组件本身基于当前props和state是否需要重新渲染组件,默认返回true。执行实际:新的props和state都会调用。不建议再该方法中深层比较影响效率。不能调用setState,会导致无限循环内存崩溃。

3. render

4. getSnapshotBeforeUpdate:再render函数后执行,dom还没有被更新。该方法返回一个Snapshot值,作为componentDidUpdate的第三个参数传入。

5. componentDidUpdate:组件更新结束后。可以获取数据 更新dom样式等。

卸载阶段:

componentWillUnmount:组件卸载之前,清理事件监听,取消网络请求等。

5. setState执行机制,第二个参数

在组件生命周期或react合成事件中,是异步。

在setTimeout或原生dom事件中,     是同步。

第二个参数是函数:

该函数会在 setState 函数调用完成并且组件开始重渲染之后被调用,可以用该函数来监听渲染是否完成。相当于componentDidMount

this.setState(
    { username: 'tylermcginnis33' },
    () => console.log( 'setState )
)

补充:哪些方法会触发react重新渲染以及如何避免不必要的重新渲染?

  • 触发react重新渲染:会导致组件包括子组件全都重新渲染

                setState() useState被调用。

                props发生变化。

                组件依赖的context发生变化。

                自定义的hook发生变化。

                forceUpdate强制组件更新。

  • 如何避免:

                React.memo:包裹函数组件,react渲染之前会对属性浅比较,如果没有变化重新渲染。第二个参数是一个可选函数,该函数接收新旧props两个值,返回false则更新组件,返回true不更新。

                useMemo:缓存函数返回的一个结果。

                useCallback:缓存函数。

                key:key的作用增加复用。

                React.PureComponent/shouldComponentUpdate:类组件的控制是否重新渲染组件。

6. React Hooks

6.1.useState

用于保存组件状态,并触发页面更新。每次执行setState() 方法,都会使得函数组件重新运行一遍

// 首先要引入useState
import react, { useState } from 'react'

export default function App () {
    // useState要赋初值,并且返回一个数组,
    // 该数组第一项name就是‘zhangsan’ ,
    // 第二项setName 是一个函数,是改变前者的唯一方法。
    const [ name, setName ] = useState('zhangsan')
     
    return (
        <div> app </div>
    )
}

需要注意的是:使用setName()修改name的值,需要直接替换式写法:setName('lisi'), 'lisi'直接把‘zhangsan’替换了。如果是数组,不要用push直接追加,setList([...list, newDate]) 用这种方法。

6.2. useEffect - 副作用函数

作用:想要在函数组件里,某方法只运行一次,或监听某数据变化就执行,使用useEffect()

执行时机:整个页面渲染完(dom树和css树组合成的渲染树)才执行useEffect里面的代码。

6.2.1.useEffect如果只传第一个回调函数,不传第二个参数,则每次函数重新渲染都会执行。浪费性能

// 首先要引入useEffect
import react, { useState, useEffect } from 'react'

export default function App () {
    const [ list, setList ] = useState([])
    // 接收两个参数,第一个函数,App函数每次重新渲染都会执行axios
    useEffect(()=>{
      axios.get('api/123').then((res)=> {
          setList(res.data.data)
      })
    })
     
    return (
        <div> app </div>
    )
}

6.2.2 useEffect第二个参数为空数组,第一个回调函数只在组件第一次渲染时运行一次。

// 首先要引入useEffect
import react, { useState, useEffect } from 'react'

export default function App () {
    const [ list, setList ] = useState([])
    // 接收两个参数,第一个函数,第二个数组。
    useEffect(()=>{
      axios.get('api/123').then((res)=> {
          setList(res.data.data)
      })
    },[])
     
    return (
        <div> app </div>
    )
}

6.2.3 组件第一次运行,依赖变化再次执行。

// 首先要引入useEffect
import react, { useState, useEffect } from 'react'

export default function App () {
    const [ name, setname ] = useState('zhangsan')
    // 每次name变化,都会执行
    useEffect(()=>{
      setName(name.splice(0,1))
    },[name])
     
    return (
        <div> app </div>
    )
}

6.2.4 模拟组件销毁生命周期钩子

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

export default function App () {
    const [ name, setname ] = useState('zhangsan')
    useEffect(()=>{
        const timer = setInterval(()=> {
            console.log(1)
        })
        // return里的代码会在此组件销毁之前执行,注意第二参数数组必须为空。
        return () => {
            clearInterval(timer)
        }
    },[]) // 数组必须为空
     
    return (
        <div> app </div>
    )
}

useEffect()不是生命周期!可以在函数组件中使用多次。

补充:useLayoutEffect() 是在dom树渲染完毕后立马执行,可以防止页面抖动,但影响加载速度。

重要补充:useEffect是怎么判断依赖项变化的?

        使用了===全等运算符判断的,如果依赖项是数组或对象,即使值没有变化,引用地址也会变化,导致每次判定结果不一样引起第一个回调函数的执行。如果这些对象或者数组没有变化,但是组件重新渲染时会被重新创建,即使依赖项没有变化,useEffect也会重新执行。使用useMemo或useCallback避免。

6.3.useCallback()记忆函数 - 优化提升性能

useState也是记忆函数,因为每次使用useState中的set方法就会引起整个组件的重新执行(普通函数、普通变量都会被重新执行),但是记忆函数可以保存住原来更改过的值,不会导致每次都是初始值。

6.4.useMeno - 类似于vue计算属性

类似于计算属性,会返回一个结果。

import { useMemo } from 'react';
import { filterTodos } from './utils.js'

export default function TodoList({ todos, theme, tab }) {
  const visibleTodos = useMemo(
    () => filterTodos(todos, tab),
    [todos, tab] // 依赖项必须要
  );
  return (
    <div className={theme}>
      <p><b>Note: <code>filterTodos</code> is artificially slowed down!</b></p>
      <ul>
        {visibleTodos.map(todo => (
          <li key={todo.id}>
            {todo.completed ?
              <s>{todo.text}</s> :
              todo.text
            }
          </li>
        ))}
      </ul>
    </div>
  );
}

6.5.useRef

功能一:保存变量

因为setState会重新更新整个组件,所以定义普通变量保存不住,每次拿到的都是初始化的值。

import { useRef } from 'react';

export default function Form() {
  let count = useRef(0); // 传初始值

  function handleClick() {
    count.current++
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        点我加1
      </button>
    </>
  );
}

功能二:类似于React.ceateRef(),获取组件实例或dom元素

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null); // 传null 或 什么都不传

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        聚焦输入框
      </button>
    </>
  );
}

6.6.useContext - 优化 减少组件层级

优化context跨组件传值的复杂写法。

import React, { useContext } from 'react';

// 第一步:引用react的createContext函数,并确保跨组件传值使用的是同一个createContext()
const GlobalContext = React.createContext() 

export default function GrandFather() {
  const [name, setName] = setState('lisi)

  return (
    // 第二步 context的提供者标签,并传入value
    <GlobalContext.Provider 
      value={{name:'zhansg', changeName:(value) => setName(value)}}
    >
      <Father/>
    </GlobalContext.Provider>
  );
}

export default function Father() {
  return (
     <Son/>
  );
}

export default function Son() {
    // 第三步:使用useContext函数包裹GlobalContext,然后直接使用。
    const value = useContext(GlobalContext)
  return (
    <div onClick={()=>value.changeName(value.name)}>
        value.name
    </div>
  );
}

6.7.useReducer - 常与useContext搭配使用

跨组件传值工具

import React, { useContext, useReducer } from 'react';

// 第二步:初始reducer的值
const initalValue = {
    count:1,
}
// 第三步,接收两个参数,第一个是之前的值(老值),第二个是action收到dispatch的类型
const reducer = (pervState, action) => {
    // 必须用新值代替旧值
    const newValue = {...pervState}
    switch(action.type) {
        case 'plus':
            newValue.count++
            return newValue
        case 'minus':
            newValue.count--
            return newValue
        case 'a':
            newValue.count = action.value
        // 默认条件下返回原数据
        default:
            return pervState
    }

}
// 第一步,useReducer接收两个参数,第一个是处理函数,第二个是初始值
// 返回一个数组,第一个值,第二个是更改reducer的dispatch方法。
const [state, disptch ] = useReducer(reducer, initalValue)

// 第四步:引用react的createContext函数,并确保跨组件传值使用的是同一个createContext()
const GlobalContext = React.createContext() 

export default function GrandFather() {
  const [name, setName] = setState('lisi)

  return (
    // 第五步 context的提供者标签,并传入value
    <GlobalContext.Provider 
      value={state, dispatch} // 这里的state和dispatch是上面useReducer返回的。
    >
      <Father/>
    </GlobalContext.Provider>
  );
}

export default function Father() {
  return (
     <Son/>
  );
}

export default function Son() {
  // 第六步:使用useContext函数包裹GlobalContext。
  const {state, dispath}= useContext(GlobalContext)
  return (
    // dispatch的语法 dispatch({type:'',value:data})
    <div onClick={()=>dispatch({type: 'a'})}>
        state.count
    </div>
  );
}

6.8.自定义Hooks

就是对逻辑的抽离,便于维护和理解。公共的逻辑可以复用。

优点:可以使用react的一些方法比如useState useEffect等。

通常会有return。

7. React + TS

7.1.类组件中使用ts

import React,{Component} from "react";

interface IProps {
    name: string,
}
interface IState {
    age: nunber,
}

// React的 Component组件可以接受两个泛型,第一个是props类型,第二个是state类型
export default class Hello extends Component<IProps,IState>{
  
  state = { age: 18 }

  render(){
    return(
      <div>
       {this.props.name} - {this.state.age}
      </div>
    )
  }
}

7.2.函数组件使用ts

import React from 'react'

interface IProps {
    name: string,
    cb?: () => void,
}

// 重点是这个React.FC<T> T是props类型
const App:React.FC<IProps> = (props) => {

    const [ name, setName ] = useState<string>('zhangsan')

    return (
        <div>{props.name}</div>
    )
    
}

8.react-router @6

8.1 一级路由与多级路由

8.2 路由重定向

8.2.1 重定向方法一:

注意 <Navigate> 组件是从react-router中引入的。

8.2.2 重定向方法二:

自定义Redirect组件

import { useEffect } from 'react'

import { Route, useNavigate } from 'react-router'

8.2.3 404页面

path="*" 就是匹配路径和所有定义的不同时,进入的404组件

8.3 路由嵌套

8.4 声明式导航与编程式导航

query传参:

8.5 动态路由

import { Route, useNavigate, useParams } from 'ract-router'

const navigate = useNavigate()

8.6 路由拦截

用到了react插槽概念,即插槽的组件在 props的children属性中。

8.7 路由模式

8.8 路由懒加载

用到了react的lazy方法和Suspense标签。

8.9 useRoutes钩子配置

类似于vue-router的配置方法配置路由:

useRoutes钩子直接返回一个组件,我们可以直接在app组件中使用该组件

import element from '@/route/index'

function App () {

    return element
}

9.react-redux@7

9.1 redux三大原则

1. 单一数据源。

2. state是只读的。

3. 使用纯函数来执行修改。

9.2 react-redux使用流程

9.2.1 redux流程:- flux运行原理

描述:

在react组件中通过dispath方法传一个类型type和数据,store也就是redux接收之后,触发reducer中对应type的action,reducer第一个参数是previousState且必须初始化赋值,第二个参数就是action,在此reducer 中必须返回一个新的value。

9.2.2 总流程:

1.创建reducer

2. 将多个reducer合并起来:combineReducers 方法

3. 使用redux的 createStore方法创建store,applyMiddleware方法使用中间件

redux中间件有:redux-thunk,让redux可以使用异步调接口。redux-promise,相同。

4. 创建actions

action必须是一个函数,返回一个函数(高阶函数),上面是同步和异步的写法。

5. 使用react-redux的Provider标签包裹整个项目。并传入store

6.使用:

方式一:connet(mapStateToProps,mapDispatchToProps)(组件名)写法。

mapStateToProps:映射store的state                  到组件的props中。

mapDispatchToProps: 映射dispath(action)   到组件的props中。

这样 store的state和dispath就可以从props中获取了。

方式二:使用react-redux的hooks。

获取store的state的hooks:import { useSelector } from 'react-redux'

获取store的dispath的hooks:import { useDispatch } from 'react-redux'

9.2.3 redux-toolkit包,更像是vuex和pinia。

此包时redux为我们自动安装thunk logger devTool中间件,不需要我们手动安装了。

优点:相对于传统方法,toolkit可以让我们在reducer中直接修改state,传统方法中state是不可变的只能用新值代替旧值。

具体使用:

第一步:创建slice,类似于vuex的各个模块。引入createSlice函数

// 'store/features/counterSlice'

import { createSlice } from '@reduxjs/toolkit';
​
export const counterSlice = createSlice({

 name: 'counter', // 命名空间,在调用action的时候会默认的设置为action的前缀

 // 初始值
 initialState: {
 count: 1,
 title: 'redux toolkit pre',
  },

 // 这里的属性会自动的导出为actions,在组件中可以直接通过dispatch进行触发
 reducers: {
   increment(state, { payload }) {
     // console.log(action);
     state.count = state.count + payload.step; // 内置了immutable
   },
   decrement(state) {
     state.count -= 1;
   },
  },
});
​
// 导出actions
export const { increment, decrement } = counterSlice.actions;
​
// 内置了thunk插件,可以直接处理异步请求
export const asyncIncrement = (payload) => (dispatch) => {
 setTimeout(() => {
 dispatch(increment(payload));
  }, 2000);
};
​
export default counterSlice.reducer; // 导出reducer,在创建store时使用到

第二部:创建store:使用工具包中的configureStore函数

// 'store/index.ts'

import { configureStore } from '@reduxjs/toolkit';
import counterSlice from './features/counterSlice';
import movieSlice from './features/movieSlice';
​
// configureStore创建一个redux数据
export default configureStore({
 reducer: {
   counter: counterSlice,
   movie: movieSlice,
  },
});

第三步:在入口文件index.ts中引用store

import React from 'react';
import ReactDOM from 'react-dom';

// 引入Provider
import { Provider } from 'react-redux';
import './index.css';
import App from './App';

// 引入创建的store
import store from './store';
​
ReactDOM.render(
 // 关键:
 <Provider store={store}>
 <App />
 </Provider>,
 document.getElementById('root')
);

第四步:在组件中使用:

// 'src/app.tsx'

import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, asyncIncrement } from './store/features/counterSlice'; // 引入actions
​
function App() {

 // 使用useSelector获取store的state
 const { count } = useSelector((state) => state.counter);

 // 使用useDispath 调用reducer中的 action
 const dispatch = useDispatch();

 return (
   <div className='App'>
     <button
       onClick={() => {
         dispatch(increment({ step: 2 })); // dispatch派发action
       }}
     >
       {count}
     </button>
   <hr />
   <button
     onClick={() => {
       dispatch(asyncIncrement({ step: 1 }));
     }}
   >
     {count}
   </button>
 </div>
  );
}
​
export default App;

10.react性能优化总结

避免不必要的 render - 避免每次更新state props重新渲染dom、创建函数或对象。

  • 生命周期render shouldComponentUpdate()  useEffect 中禁止setState或useState
  • 避免使用内联函数,建议使用函数定义与箭头函数。
  • 使用react Fragment 减少标签
  • 路由懒加载 (React.lazy与React.Suspense fallback)
  • 使用useCallback useMemo React.Memo优化性能。

  • 31
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作为前端使用React、TypeScript、React Router、Redux、Axios、Ant Design和Sass开发ERP软件项目的职责描述,主要包括以下几个方面: 1. 分析需求和设计界面:与产品经理、设计师等团队成员合作,分析用户需求和产品设计,设计符合用户需求的界面,并提供良好的用户体验。 2. 使用React和TypeScript开发组件:根据设计稿或需求文档,使用React和TypeScript开发可复用的组件,利用类型检查提高代码的可靠性和可维护性。 3. 使用React Router实现路由管理:使用React Router进行页面之间的导航和路由管理,确保页面之间的跳转和参数传递的正常。 4. 使用Redux进行状态管理:使用Redux进行全局状态的管理,包括定义和处理数据流、异步操作、状态持久化等,确保数据的一致性和可控性。 5. 使用Axios进行网络请求:使用Axios库发送HTTP请求与后端API进行数据交互,并处理请求的错误和异常情况。 6. 使用Ant Design进行UI开发:使用Ant Design提供的组件库进行界面开发,保证界面的一致性和美观性,并根据需求进行自定义样式。 7. 使用Sass进行样式管理:使用Sass预处理器编写可复用的样式代码,提高样式开发效率,并保持样式的可维护性。 8. 优化性能和用户体验:通过前端优化技术(如代码分割、懒加载、缓存等),提升ERP软件的性能和用户体验,确保页面加载速度快、操作流畅。 9. 跨浏览器兼容性测试:测试并确保ERP软件在各种主流浏览器(如Chrome、Firefox、Safari等)下的正常运行,并解决兼容性问题。 10. 代码版本管理和团队协作:使用版本管理工具(如Git)管理代码,与团队成员协作开发,参与代码评审和项目迭代。 11. 系统维护和故障排除:及时响应用户反馈并解决软件中出现的前端问题,修复bug,确保ERP软件的稳定运行。 总的来说,前端使用React、TypeScript、React Router、Redux、Axios、Ant Design和Sass开发ERP软件项目的职责是负责开发和维护ERP软件的前端界面和功能,与后端进行数据交互,优化性能和用户体验,并与团队成员协作推动项目的成功交付。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值