【问题标题】:Use async/await in React component在 React 组件中使用 async/await
【发布时间】:2023-03-31 01:18:01
【问题描述】:

直接在 React 组件中使用 async/await 然后将结果存储在 store 中是一种好习惯吗?例如:

class User extends Component {

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

    componentWillMount() {
        this.getUser();
    }

    async getUser() {
        try {
            const user = await userAction.get();
            this.props.storeUser(user);
        } catch (err) {}
    }
}

const state2props = (state) => ({
    user: state.User.user
});

const dispatch2props = dispatch => ({
    storeUser: (user) => dispatch(userReducer.store(user)),
});

export default connect(state2props, dispatch2props)(User);

它似乎比经典的 react/redux 模式更灵活。

【问题讨论】:

    标签: reactjs redux async-await


    【解决方案1】:

    是的,您可以在 React 组件中使用 async/await。这不是一个坏习惯 这只是架构问题。

    有很多方法可以在应用程序中实现异步逻辑。在小型应用程序中,您可以在反应组件中实现异步逻辑。当您的应用程序长大后,您会遇到一些问题,例如重复代码(例如,您想在多个 React 组件中获取用户)、代码组合和代码拆分。

    您可以使用 redux-thunk https://github.com/gaearon/redux-thunk、redux-saga https://github.com/redux-saga/redux-saga、redux-logic https://github.com/jeffbski/redux-logic 或任何其他解决方案。

    此外,您可以创建自己的自定义中间件,例如:

    const reactions = {};
    
    export const addReactions = signals => {
      reactions = { ...reactions, ...signals };
    };
    
    export default (signalMiddleware = ({ getState, dispatch }) => next => action => {
      if (!action.signal) {
        return next(action);
      }
    
      if (!reactions[action.signal]) {
        throw new Error(`There is no handler for ${action.signal} signal`);
      }
    
      reactions[action.signal]({ getState, dispatch, payload: action.payload });
    });

    这样的中间件允许您将业务逻辑实现到单独的层中。例如:

    import { addReactions } from './path/to/signalMiddleware';
    
    // Describe your Actions for middleware:
    const fetchUser = (id) => ({
        signal: 'FETCH_USER',
        payload: id
    });
    
    const anotherAction = () => ({
        signal: 'SOME_ANOTHER_ACTION_WITH_USER',
    });
    
    
    // Describe your business logic using middleware:
    
    addReactions({
        FETCH_USER: async ({dispatch}, {id}) => {
            const user = await fetcher.get(id);
            dispatch({
                type: 'RECEIVE_USER',
                payload: user,
            });
        },
        SOME_ANOTHER_ACTION_WITH_USER: () => {
           // do some awesone job :)
        }
    }) 

    所以我们的反应组件可能是:

    class User extends Component {
    
        render() {
            return <div>{this.props.user.name}</div>
        }
    
        componentDidMount() {
           this.props.dispatch(fetchUser(123));
        }   
    }
    
    export default connect(state2props, dispatch2props)(User);

    现在您可以将您的应用架构分为 3 层:

    1) 视图——反应组件

    2) 业务逻辑——你的中间件

    3) 数据逻辑——你的 reducer

    在视图和业务层之间,我们使用带有 signal 字段和不带 type 字段的特定操作。 在业务和数据逻辑之间,我们使用带有type 字段的操作。

    这种架构允许您严格分离层。这种架构在大型应用程序中很有用。

    在小型应用程序中,可以使用 redux-thunk 或在 react-components 中编写异步逻辑。

    【讨论】:

    • 我理解这种方法,但是如果我有 2 个组件消耗用户,并且在其中一个组件中我想在获取用户后做一些特别的事情(例如更改窗口位置)怎么办?按照这个逻辑,做起来似乎很棘手。
    • 可以在componentWillReceiveProps中添加这样的逻辑。收到用户后,将调用 componentWillReceiveProps。您还可以将公共代码移动到单独的函数并使用signal 字段创建多个操作。描述架构的主要目标是排除重复。
    • 这是我正在做的事情,但在我的情况下,这种特殊动作经常附加。这对我来说似乎有点hacky。无论如何感谢您的详细回答!
    • 我有一个想法:如果你有很多特定的情况,你可以尝试创建一个带有承诺的信号动作:const fetchUser = (id) =&gt; ({signal: "FETCH_USER", payload: id, promise: new Promise})。 Redux 调度函数返回一个调度的动作。因此,您可以在 react 组件中处理 promise 并在此处粘贴您的自定义逻辑。但是你必须直接在你的中间件布局中解决 promise。
    猜你喜欢
    • 2023-03-24
    • 2023-03-04
    • 2019-09-09
    • 2019-04-24
    • 2017-10-02
    • 2020-04-22
    • 2016-07-31
    相关资源
    最近更新 更多