使用useReduer代替redux

1,026 阅读2分钟

在之前的开发和学习中, 对redux 一直觉得很难用, 然后又不得不用, 于是就翻博客学习,下面正式开始

使用react-cli初始化项目, 然后在src新建index.js

import ReactDOM from 'react-dom';

function App() {
    return (
        <div>app</div>
    )
}

ReactDOM.render(<App />, document.getElementById('root'))

运行项目,yarn start 可以看到 浏览器中出现app 就初始化好了

新建books, music, user 三个组件 , ,并在index 中引入三个组件 并展示

  • books, music, user
function Books() {
    return (
        <div>
            <h1>Books</h1>
        </div>
    )
}

export default Books;
function User() {
    return (
        <div>
            <h1>User</h1>
        </div>
    )
}

export default User;
function Music() {
    return (
        <div>
            <h1>Music</h1>
        </div>
    )
}

export default Music;
  • 然后在app 中引入
import Books from "./books/books";
import User from "./user/user";
import Music from "./music/music";

function App() {
    return (
        <div>
            <User />
            <hr>
            <Books />
            <Music />
        </div>
    )
}

ReactDOM.render(<App />, document.getElementById('root'))

  • 看看运行结果

WechatIMG1.png

在src目录新建context 文件, 并在app 中引入

import {createContext} from 'react'

const AppContext = createContext(null);

export default AppContext;

在index 中引入context , 并添加initState


import ReactDOM from 'react-dom';
import Books from "./books/books";
import User from "./user/user";
import Music from "./music/music";
import AppContext from "./context/context";

const initState = {
    books: null,
    music: null,
    user: null
}

function App() {
    return (
        <div>
            <User />
            <hr/>
            <Books />
            <Music />
        </div>
    )
}

ReactDOM.render(<App />, document.getElementById('root'))

在src下新建reducers目录, 添加 user_reducer.js , book_reducer.js, music_reducer.js


export default {
    getBooks: (state, action) => {
        return {...state,books: action.books}
    }
}
export default {
    getMusic: (state, action) => {
        return {...state, music: action.music}
    }
}
export default {
    getUser: (state, action) => {
        return {...state, user: action.user}
    }
}

在index 文件中引入reducer, 并新建recuderConfig, 配合context, 完成 reducer 初始化

import ReactDOM from 'react-dom';
import Books from "./books/books";
import User from "./user/user";
import Music from "./music/music";
import AppContext from "./context/context";
import bookReducer from "./reducers/book_reducer";
import musicReducer from "./reducers/music_reducer";
import userReducer from "./reducers/user_reducer";
import {useReducer} from "react";

const initState = {
    books: null,
    music: null,
    user: null
}

const reducerConfig = {
    ...bookReducer,
    ...musicReducer,
    ...userReducer
}

const reducer = (state, action) => {
    const dispatchFn = reducerConfig[action.type];

    if (dispatchFn) {
        const storeState = dispatchFn(state, action);
        return storeState;
    } else {
        throw  new Error('不认识');
    }
}

function App() {

    const [state, dispatch] = useReducer(reducer, initState);

    return (
        <AppContext.Provider value={{state, dispatch}}>
            <User />
            <hr/>
            <Books />
            <Music />
        </AppContext.Provider>
    )
}

ReactDOM.render(<App />, document.getElementById('root'))

在src目录新建ajax.js 模拟请求

// 假 ajax
// 两秒钟后,根据 path 返回一个对象,必定成功不会失败
function ajax(path) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (path === "/user") {
          resolve({
            id: 1,
            name: "笑嘻嘻"
          });
        } else if (path === "/books") {
          resolve([
            {
              id: 1,
              name: "JavaScript 高级程序设计"
            },
            {
              id: 2,
              name: "JavaScript 精粹"
            }
          ]);
        } else if (path === "/movies") {
          resolve([
            {
              id: 1,
              name: "爱在黎明破晓前"
            },
            {
              id: 2,
              name: "恋恋笔记本"
            }
          ]);
        }
      }, 2000);
    });
  }
  
  export default ajax;

在user组件中使用ajax, 并渲染数据

function User() {

    const {state, dispatch} = useContext(AppContext);

    useEffect(()=> {
        ajax('/user').then(res => dispatch({type: "getUser", user: res}))
    }, [])

    return (
        <div>
            <h1>User</h1>
            <div>{state?.user ? state?.user?.name : '加载中' }</div>
        </div>
    )
}

export default User;

在 books 中引入, 并渲染

import AppContext from "../context/context";
import ajax from "../ajax";
import {useContext, useEffect} from "react";

function Books() {
    const {state, dispatch} = useContext(AppContext);

    useEffect(()=> {
        ajax('/books').then( res => dispatch({type: 'getBooks', books: res}))
    }, [])
    return (
        <div>
            <h1>Books</h1>
            <div>
                {state?.books?.length > 0 ?  state?.books?.map( item => (<div>{item.name}</div>)) : '加载中'}
            </div>
        </div>
    )
}

export default Books;

到此已经完成 使用useReduer 实现redux 了