指南

使用useReducer和useContext实现状态管理

在React中状态管理可以使用Redux,Recoil等库,在16.8之后使用Hooks之后,可以使用更多的Hooks函数来实现状态管理,此处结合useReducer和useContext实现简单的数据状态管理。

// stateReducer.js
const state = { count: 0 };

const StateContext = React.createContext();

const reducer = (preState, action) => {
    switch (action.type) {
        case 'inc':
            return { ...preState, count: preState.count }
    }
}

export const ReducerContextProvider = (props) => {
    const [state, dispatch] = useReducer(reducer, deviceState)
    return (
        <StateContext.Provider value={{ state, dispatch }}>
            {props.children}
        </StateContext.Provider>
    );
};

export const useReducerContext = () => {
    return useContext(StateContext);
}

以上设置了Context,可以在子组件中使用:

// Home.jsx
const Home = (props) => {
    const { state, dispatch } = useReducerContext();

    return <div>
        <button onClick={() => dispatch({ type: 'inc' })}>getDevInfoAll</button>
        <p> {state.count} </p>
    </div>

}

export default Home;

在根组件中设置:

// index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    // <React.StrictMode>
    <DeviceReducerContextProvider>
        <Home />
    </DeviceReducerContextProvider>
    // </React.StrictMode>
);

注意:

其中React.StrictMode启用严格模式后,会使得一些钩子函数重复调用(double invoke),该严格模式在开发环境中运行,生产环境中不影响。
React.StrictMode是一个用来突出显示应用程序中潜在问题的工具,与 Fragment 一样,StrictMode 不会渲染任何可见的 UI。它为其后代元素触发额外的检查和警告,详细见Strict Mode – React (reactjs.org),以下为简单摘要:

Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method
Function component bodies
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer

Note:
This only applies to development mode. Lifecycles will not be double-invoked in production mode.

设置React项目中@为根目录

找到node_modules/react-scripts/config/webpack.config.js
修改alias闭包

alias: {
    '@': path.resolve('src')
    //以上行为新增路径,在以后的代码中使用@即可代替src路径
    // Support React Native Web
    // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
    'react-native': 'react-native-web',
    // Allows for better profiling with ReactDevTools
    ...(isEnvProductionProfile && {
        'react-dom$': 'react-dom/profiling',
        'scheduler/tracing': 'scheduler/tracing-profiling',
    }),
    ...(modules.webpackAliases || {}),
    }

在tsconfig中同时设置:

{
    "compilerOptions": {
        "baseUrl": "./",
            "paths": {
            "@/*": [
                "./src/*"
            ]
        },
    }
}
CRA创建项目

使用create-react-app可以方便创建React项目,此处演示使用CRA创建js/ts类型项目,此处使用Hook类型项目:

  1. 安装CRA到Node的根目录下,安装后可以直接用命令行创建项目
$ npm install -g create-react-app
  1. 安装后使用npx执行安装包(npx可以参考NodeJS笔记下的:NPM和NPX)
  2. 创建JavaScript类型
$ npx create-react-app my-app
  1. 创建TypeScript类型(推荐)
$ npx create-react-app my-app --template typescript
测试

安装依赖(package.json)

$ yarn install
运行
$ yarn start

样例:

// JavaScript
// index.jsx

const App = (props) => {
    return <div>Hello,React!</div>
}

export default App;

// Typescript
// index.tsx

export interface AppProps {
    name?: string;
}

const App: React.FC<AppProps> = (props) => {
    return <div>Hello,TS!</div>
}
修改CRA Webpack

默认情况下,用create-react-app创建的Webpack会默认隐藏,如果要修改配置,可以有几种方式:

  • 使用eject

该方式是一次性操作,无法回撤,如果使用该选项,CRA的优势就会降低,使用方法如下:

$ npm run eject
  • 使用react-app-rewired (推荐)

安装该依赖:

$ npm install customize-cra react-app-rewired @babel/plugin-proposal-decorators

修改package.json:

/* package.json */
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom",
"eject": "react-scripts eject"
}

配置config-overrides.js:
在项目根目录下创建一个config-overrides.js文件,添加如下内容:

/* config-overrides.js */
const path = require('path')
const { override, addDecoratorsLegacy, addWebpackAlias } = require('customize-cra')
function resolve(dir) {
    return path.join(__dirname, '.', dir)
}
module.exports = override(
    // 装饰器
    addDecoratorsLegacy(),
    addWebpackAlias({
        '@': resolve('src'),
        '@comps': resolve('src/components'),
        '@style': resolve('src/assets/style'),
        '@images': resolve('src/assets/images'),
        '@pages': resolve('src/pages'),
    })
)

运行:

$ npm start
库使用

Antd Table Warning: Each child in a list should have a unique "key" prop.
该问题主要是由于Table组件提供了rowKey属性,增加该属性即可:

<Table 
    rowKey={record => record.id} 
    columns={columns} 
    dataSource={roleDataList} />
最后修改:2023 年 07 月 05 日
如果觉得我的文章对你有用,请随意赞赏