Reactjs常用组件

1 react

1.1 useState

让函数组件具有维持状态的能力

const[count, setCount]=useState(0);

1.2 useEffect

执行副作用,useEffect 的第二个参数告诉 React 用到了哪些外部变量

类似于Vue watch的作用

useEffect(fn, deps);

1.每次 render 后执行:不提供第二个依赖项参数。

比如useEffect(() => {})。

2.仅第一次 render 后执行:提供一个空数组作为依赖项。

比如useEffect(() => {}, [])。

3.第一次以及依赖项发生变化后执行:提供依赖项数组。

比如useEffect(() => {}, [deps])。

4.组件 unmount 后执行:返回一个回调函数。

比如useEffect() => { return () => {} }, [])。

useEffect(() => {
  document.title = "Hello, " + name;
}, [name]);

1.3 useCallback

缓存回调函数。

useCallback(fn, deps)

useCallback是React Hooks中的一个函数,用于优化函数组件的性能。它的作用是返回一个memoized(记忆化的)函数,这个函数只有在依赖项发生变化时才会重新计算,否则会直接返回上一次计算的结果。

例子:

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

function Counter() {
  const [count, setCount] = useState(0);
  const handleIncrement = useCallback(
    () => setCount(count + 1),
    [count], // 只有当 count 发生变化时,才会重新创建回调函数
  );
  return <button onClick={handleIncrement}>+</button>
}

例子2:

import { useState, useCallback } from 'react';

function MyComponent(props) {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log(`Clicked ${count} times`);
  }, [count]);

  return (
    <>
      <div>Count: {count}</div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={handleClick}>Click me</button>
    </>
  );
}

1.4 useMemo

缓存计算的结果,类似于Vue中computed的作用

useMemo(fn, deps);

1.5 useRef

在多次渲染之间共享数据

const myRefContainer =useRef(initialValue);

1.6 useContext

定义全局状态

很多状态管理框架,比如 Redux,正是利用了 Context 的机制来提供一种更加可控的组件之间的状态管理机制。

1.7 createRef

创建一个 React ref 对象

import React, { createRef } from 'react';

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    // 创建一个 ref 对象
    this.myRef = createRef();
  }

  render() {
    return (
      <div>
        {/* 将 ref 对象附加到一个 DOM 元素上 */}
        <input type="text" ref={this.myRef} />
      </div>
    );
  }
}

1.8 memo

React.memo 是 React 提供的一个高阶组件(Higher-Order Component),用于优化函数组件的性能。它类似于类组件中的 shouldComponentUpdate 方法,用于在 props 发生变化时判断是否重新渲染组件。

import React from 'react';

const MyComponent = React.memo((props) => {
  // 在这里定义组件逻辑
  return (
    <div>
      {/* 使用 props 中的数据渲染组件 */}
      <h1>{props.title}</h1>
      <p>{props.content}</p>
    </div>
  );
});

1.9 组件创建

const ImgUpload: FC<IProps> = (props: IProps): ReactElement => {
    return (<div></div>)
};
export default memo(ImgUpload);

1.10 Suspense

就是一种加载组件优化,提升用户体验。

children:真正的 UI 渲染内容。

fallback:真正的 UI 未渲染完成时代替其渲染的备用 UI,它可以是任何有效的 React 节点。

import { Suspense } from 'react';
<Suspense fallback={<Loading />}>
  <SomeComponent />
</Suspense>

2 Redux Toolkit

2.1 createSlice

接受初始状态的函数、reducer 函数的对象和"切片名称", 并自动生成与 reducer 和 state 相对应的动作创建者和动作类型。类似于 Vue 中 Vuex 中的 store

function createSlice({
    //此状态切片的字符串名称。生成的操作类型常量将使用此作为前缀。
    name: string,
    // 此状态切片的初始状态值。
    initialState: State,
    //一个包含 Redux "case reducer" 函数的对象
    reducers: Record<string, ReducerFunction | ReducerAndPrepareObject>,
    // A "builder callback" function used to add more reducers
    extraReducers?: (builder: ActionReducerMapBuilder<State>) => void,
    // A preference for the slice reducer's location, used by `combineSlices` and `slice.selectors`. Defaults to `name`.
    reducerPath?: string,
    // An object of selectors, which receive the slice's state as their first parameter.
    selectors?: Record<string, (sliceState: State, ...args: any[]) => any>,
})

例子:

import { createSlice } from '@reduxjs/toolkit'

const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  reducers: {
    increment: (state) => state + 1,
  },
})

2.2 createAsyncThunk

一个接受 Redux 操作类型字符串的函数和一个应该返回 promise 的回调函数。通常用于处理异步逻辑。

// 创建一个异步的 Thunk action creator
export const getUserById = createAsyncThunk(
  'user/getUserById', // 定义 action 的 type
  async (userId) => {
    // 异步逻辑,例如从服务器获取数据
    const response = await fetchUserById(userId);
    // 返回获取到的数据作为 action payload
    return response.data;
  }
);

2.3 createAction

在 Redux 中定义动作的常用方法是分别声明一个动作类型 常量和一个动作创建器函数来构造该类型的动作。与createAsyncThunk区别是:一个同步一个异步。

const INCREMENT = 'counter/increment'

function increment(amount: number) {
  return {
    type: INCREMENT,
    payload: amount,
  }
}

const action = increment(3)
// { type: 'counter/increment', payload: 3 }

2.4 createReducer

用于创建 Redux 中的 reducer

  • initialState :第一次调用 reducer 时应使用的初始状态。这也可能是一个"延迟初始值设定项"函数,该函数在调用时应返回初始状态值。每当调用 reducer with 作为其状态值时,都会使用它,并且主要用于从 中读取初始状态等情况。State | (() => State)``undefined``localStorage

  • builder回调 接收要定义的构建器 对象的回调 大小写缩减器通过调用 .(builder: Builder) => void``builder.addCase(actionCreatorOrType, reducer)

    import { createReducer } from '@reduxjs/toolkit';

    // 定义初始状态
    const initialState = {
    value: 0
    };

    // 使用 createReducer 创建 reducer
    const counterReducer = createReducer(initialState, {
    increment: (state) => {
    state.value += 1;
    },
    decrement: (state) => {
    state.value -= 1;
    },
    });

    export default counterReducer;

3 react-redux

3.1 创建项目

npx create-react-app zhiqu-web-test --template typescript

3.2 useselector

共享状态,从Redux的store中提取数据(state)

const result: any = useSelector(selector: Function, equalityFn?: Function)

selector 在概念上大约等同于 mapStateToProps argument to connect

selector 将以整个 Redux store state 作为唯一的参数被调用。每当函数组件渲染时,selector 就会被运行(除非在组件的前一次渲染后引用没有改变,这样 hooks 就会返回缓存的结果,而不是重新运行 selector)。useSelector() 也会订阅 Redux store,每当有 action 被 dispatched 时就会运行 selector。

全等比较和更新

默认的对比方式是严格的 === 引用比较

import { shallowEqual, useSelector } from 'react-redux'
const selectedData = useSelector(selectorReturningObject, shallowEqual)

结合useEffect做全局的store监听:

const channel = useSelector<any, IChannel>((state) => {
    return state.channelReducer?.channel as IChannel;
  });
useEffect(() => {
    ...
  }, [channel]);

3.3 configureStore

提供了一个简单而灵活的方式来创建 Redux store,使得 Redux 应用的设置过程更加轻松和高效。它是 Redux Toolkit 提供的一个重要工具,可以帮助开发者更快地搭建和管理 Redux 应用。

import { configureStore } from '@reduxjs/toolkit';
// ...

const store = configureStore({
  reducer: {
    posts: postsReducer,
    comments: commentsReducer,
    users: usersReducer,
  },
});

// 从 store 本身推断出 `RootState` 和 `AppDispatch` types
export type RootState = ReturnType<typeof store.getState>;
// 类型推断: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;

综合案例:使用 createSlice、createAsyncThunk 和 configureStore

import { configureStore, createSlice, createAsyncThunk } from '@reduxjs/toolkit';

// 定义一个异步 Thunk action creator
const fetchUserById = createAsyncThunk(
  'users/fetchById',
  async (userId, thunkAPI) => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
    return response.json();
  }
);

// 定义一个初始状态
const initialState = {
  user: {},
  loading: false,
  error: null,
};

// 创建一个 slice
const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    changeUser(state, { payload }) {
      state.user= payload;
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchUserById.pending, (state, action) => {
        state.loading = true;
      })
      .addCase(fetchUserById.fulfilled, (state, action) => {
        state.loading = false;
        state.user = action.payload;
      })
      .addCase(fetchUserById.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message;
      });
  },
});

// 导出 slice 中的 action creators
export const { changeUser } = userSlice.actions;

// 创建 Redux store
const store = configureStore({
  reducer: userSlice.reducer,
});

export default store;

//将其分发到 Redux store 中。这样一来,Redux store 中的相应 reducer 将会根据'changeUser' //action 的类型来更新用户信息的状态。
store.dispatch(changeUser(user));


import { type Dispatch } from 'redux';
dispatch(fetchUserById(userId));

在 Redux 应用中,store.dispatchdispatch 都用于触发 action,但它们的使用方式略有不同。

  1. store.dispatch : 用于分发 action 到 Redux store 中。它通常在组件外部被调用,比如在 Redux 相关的业务逻辑代码中或者 Redux 中间件中。示例:store.dispatch(action)

  2. dispatch : dispatch 是一个函数,通常通过 React Redux 提供的 useDispatch hook 或者 connect 函数的返回值来获取。它用于在 React 组件中分发 action。dispatch 函数本质上是 store.dispatch 的封装,用于在组件中直接触发 action,而不需要显式地引用 Redux store。示例:dispatch(action)

总的来说,store.dispatch 是 Redux store 实例的方法,用于在 Redux 应用的任意位置触发 action,而 dispatch 是一个函数,通常在 React 组件中使用,用于触发 action 并更新 Redux store 中的状态。

3.4 useDispatch

const dispatch = useDispatch()

这个 hook 返回一个对 Redux store 中的 dispatch 函数的引用。dispatch结合store使用

import React from 'react'
import { useDispatch } from 'react-redux'

export const CounterComponent = ({ value }) => {
  const dispatch = useDispatch()

  return (
    <div>
      <span>{value}</span>
      <button onClick={() => dispatch({ type: 'increment-counter' })}>
        Increment counter
      </button>
    </div>
  )
}

3.5 useStore

为什么很少使用 useStore

  • 在 React Redux 中,useStore 允许你从默认的上下文中获取当前的 Redux store 实例。然而,它在实际开发中很少被使用,因为大多数情况下,我们不需要直接访问整个 store。

  • 使用 useStore 的主要原因是为了访问 store 的状态或执行一些自定义逻辑。但是,这通常不是最佳实践,因为 React Redux 提供了更高级的 API 来处理 store 交互,例如 useSelectoruseDispatch

    import React from 'react';
    import { useStore } from 'react-redux';

    const MyComponent = () => {
    const store = useStore();

    const handleClick = () => {
      // 分发一个 action 到 Redux store 中
      store.dispatch({ type: 'SOME_ACTION' });
    
      // 获取当前 Redux store 中的状态
      const state = store.getState();
      console.log(state);
    };
    
    return (
      <button onClick={handleClick}>Dispatch Action</button>
    );
    

    };

    export default MyComponent;

3.6 useselector

共享状态,从Redux的store中提取数据(state)

const result: any = useSelector(selector: Function, equalityFn?: Function)

selector 在概念上大约等同于 mapStateToProps argument to connect

selector 将以整个 Redux store state 作为唯一的参数被调用。每当函数组件渲染时,selector 就会被运行(除非在组件的前一次渲染后引用没有改变,这样 hooks 就会返回缓存的结果,而不是重新运行 selector)。useSelector() 也会订阅 Redux store,每当有 action 被 dispatched 时就会运行 selector。

  const channel = useSelector<{ channelReducer: { channel: IChannel } }, IChannel>((state) => {
    return state.channelReducer.channel as IChannel;
  });

4 redux-immutable

4.1 combineReducers

组合reducer

import { combineReducers } from 'redux-immutable';
const reducer = combineReducers({
  loginReducer,
  channelReducer,
  queueReducer
});

5 react-router-dom

5.1 useNavigate

用于在React应用程序中进行路由导航

const navigate = useNavigate();
navigate('/register', {
      replace: false
    });

5.2 useLocation

用于获取当前页面的 URL 信息。它返回一个包含当前 URL 信息的 location 对象,包括 pathname、search、hash 等属性。

import React from 'react';
import { useLocation } from 'react-router-dom';

const MyComponent = () => {
  // 使用 useLocation hook 获取当前页面的 URL 信息
  const location = useLocation();

  return (
    <div>
      <h1>当前页面的 URL 信息:</h1>
      <p>Pathname: {location.pathname}</p>
      <p>Search: {location.search}</p>
      <p>Hash: {location.hash}</p>
    </div>
  );
};

export default MyComponent;

5.3 路由设置

路由配置:

import { Navigate, type RouteObject } from 'react-router-dom';
import { lazy, Suspense } from 'react';
const routes: RouteObject[] = [
  {
    path: '/',
    element: <Navigate to={LOGIN_PATH} />
  }
]
export { routes };

项目启动入口:

import ReactDOM from 'react-dom/client';
import App from './App';
import './assets/css/base.css';
import './constant/format';
const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(<App />);

App.tsx配置:

import { Suspense, useEffect, type ReactElement } from 'react';
import { Provider } from 'react-redux';
import 'antd/dist/reset.css';
import { HashRouter, useRoutes, useLocation, useNavigate } from 'react-router-dom';
import { routes } from './router';
import store from './store';
import './store/actionCreators';
import ErrorBoundary from './components/error';
import { CommonWrapper } from './assets/css/common';

function App(): ReactElement {
  function RouteElement(props: any) {
    return useRoutes(routes);
  }
  return (
    <CommonWrapper>
      <div className="App">
        <Provider store={store}>
          <HashRouter>
            <Suspense fallback={<div>wwww</div>}>
              <ErrorBoundary>
                <RouteElement />
              </ErrorBoundary>
            </Suspense>
          </HashRouter>
        </Provider>
      </div>
    </CommonWrapper>
  );
}

export default App;

通过useRoutes(routes)将路由加载进去

5.4 withRouter

withRouter 是 React Router 提供的一个高阶组件(Higher-Order Component),用于将路由信息注入到组件中。它可以将 React Router 的 history、location 和 match 对象作为 props 传递给被包裹的组件。

import React from 'react';
import { withRouter } from 'react-router-dom';

const MyComponent = ({ history, location, match }) => {
  // 在组件中可以访问到 history、location 和 match 对象
  return (
    <div>
      <h1>当前页面的路径:</h1>
      <p>Pathname: {location.pathname}</p>
      {/* 其他路由信息 */}
    </div>
  );
};

// 使用 withRouter 高阶组件包裹组件
export default withRouter(MyComponent);

5.5 错误页面定义

import React from 'react';
import { useNavigate } from 'react-router-dom';
function withRouter(WrapperComponent: any) {
  return function (props: any) {
    const navigate = useNavigate();
    const router = { navigate };
    return <WrapperComponent {...props} router={router} />;
  };
}
export default withRouter;

通过withRouter定义错误页面:

import React, { type ReactElement } from 'react';
import { Button, Result } from 'antd';
import withRouter from '../../hook/withRouter/withRouter';

interface IProps {
  children: ReactElement;
  router: any;
}
interface IState {
  hasError: boolean;
}
class ErrorBoundary extends React.PureComponent<IProps, IState> {
  constructor(props: any) {
    super(props);
    this.state = { hasError: false };
  }
//静态方法,用于捕获子组件渲染过程中发生的错误,并更新组件的状态。在这里,如果发生了错误,则将 hasError 状态设置为 true。
  static getDerivedStateFromError(error: any) {
    return { hasError: true };
  }
//生命周期方法,用于捕获子组件渲染过程中发生的错误,并打印错误信息。在这里,将错误信息打印到控制台。
  componentDidCatch(error: any, errorInfo: any) {
    console.log(error, errorInfo);
  }

  loginRouter(): void {
    const { navigate } = this.props.router;
    navigate('/home/recommend');
    window.location.reload();
  }

  render() {
    if (this.state.hasError) {
      return (
        <Result
          status="404"
          title="错误"
          subTitle="抱歉,页面好像出现了一个未知错误,请点击下方按钮跳转至首页"
          extra={
            <Button
              type="primary"
              onClick={() => {
                this.loginRouter();
              }}
            >
              首页
            </Button>
          }
        />
      );
    }
    return this.props.children;
  }
}

export default withRouter(ErrorBoundary);
相关推荐
学习路上_write2 分钟前
FPGA/Verilog,Quartus环境下if-else语句和case语句RT视图对比/学习记录
单片机·嵌入式硬件·qt·学习·fpga开发·github·硬件工程
非概念8 分钟前
stm32学习笔记----51单片机和stm32单片机的区别
笔记·stm32·单片机·学习·51单片机
还是大剑师兰特44 分钟前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
一只小白菜~1 小时前
web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
前端·javascript·pdf·windowopen预览pdf
方才coding1 小时前
1小时构建Vue3知识体系之vue的生命周期函数
前端·javascript·vue.js
阿征学IT1 小时前
vue过滤器初步使用
前端·javascript·vue.js
王哲晓1 小时前
第四十五章 Vue之Vuex模块化创建(module)
前端·javascript·vue.js
发现你走远了1 小时前
『VUE』25. 组件事件与v-model(详细图文注释)
前端·javascript·vue.js
吖秧吖1 小时前
three.js 杂记
开发语言·前端·javascript
前端小超超1 小时前
vue3 ts项目结合vant4 复选框+气泡弹框实现一个类似Select样式的下拉选择功能
前端·javascript·vue.js