将函数从 pure react 转换为 redux react

IT技术 javascript reactjs redux react-redux
2021-05-06 23:02:04

在纯react中,我编写了一个我调用的函数componentDidMount ()

  getTasks = (userId, query, statusTask, pageNumber) => {
    let check = {};
    axios({
      url: `/api/v1/beta/${userId}`,
      method: 'GET'
    })
      .then(res => {
        check = res.data;

        if (res.data) {
          this.setState({
            checkRunning: res.data,
            checkRunningId: res.data.id
          });
          this.utilizeTimes(res.data.task_id);
        }
      })
      .catch(error => {
        console.log(error);
      })
      .then(() => {
        const params = {
          sort: 'name'
        };

        if (query) {
          params['filter[qwp]'] = query;
          if (this.state.tasks[0]) {
            this.setState({
              selectedId: this.state.tasks[0].id,
              selectedTabId: this.state.tasks[0].id
            });
          }
        }

        axios({
          url: '/api/v1//tasks',
          method: 'GET',
          params
        })
          .then(res => {
            if (res.status === 200 && res.data) {
              this.setState({
                tasks: res.data,
                lengthArrayTasks: parseInt(res.headers['x-pagination-total-count'])
              });

              if (!check && res.data && res.data[0]) {
                this.setState({
                  selectedTabId: res.data[0].id,
                });

                this.load(res.data[0].id);
              }

              let myArrayTasks = [];
              myArrayTasks = res.data;
              let findObject = myArrayTasks.find(task => task.id === this.state.runningTimerTask.id);

              if (
                !findObject &&
                this.state.runningTimerTask &&
                this.state.runningTimerTask.id &&
                this.state.query === ''
              ) {
                this.setState({
                  tasks: [this.state.runningTimerTask, ...myArrayTasks]
                });
              }
            }
          })
          .catch(error => {
            console.log(error);
          });
      });
  };

我正在尝试将其重写为 redux,但结果不佳。首先它发出一个请求/ api / v1 / beta / $ {userId},将答案写入变量中checkcheck传到下then在接下来then执行请求'/ api / v1 // tasks' 有人可以帮我吗?我在寻求一些提示。这有点复杂吗?

到目前为止,我已经设法创建了这样的东西:

店铺

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers';

const store = createStore(rootReducer, applyMiddleware(thunk));

export default store;

行动

export const RUNNING_TIMER = 'RUNNING_TIMER';
export const GET_TASKS = 'GET_TASKS';
export const FETCH_FAILURE = 'FETCH_FAILURE';

export const runningTimer = (userId, query, statusTask, pageNumber) => dispatch => {
  console.log(userId);
  axios({
    url: `/api/v1/beta/${userId}`,
    method: 'GET'
  })
    .then(({ data }) => {
      dispatch({
        type: RUNNING_TIMER,
        payload: data
      });
    })
    .catch(error => {
      console.log(error);

      dispatch({ type: FETCH_FAILURE });
    })
    .then(() => {
      const params = {
        sort: 'name'
      };

      axios({
        url: '/api/v1//tasks',
        method: 'GET',
        params
      })
        .then(({ data }) => {
            dispatch({
                type: GET_TASKS,
                payload: data
            });
        })
        .catch(error => {
            console.log(error);
        });
    });
};

减速器

import { RUNNING_TIMER, GET_TASKS } from '../actions';

const isRunningTimer = (state = {}, action) => {
  const { type, payload } = action;
  switch (type) {
    case RUNNING_TIMER:
      return {
        checkRunningTimer: payload,
        checkRunningTimerId: payload && payload.id ? payload.id : null
      };
      break;
      case GET_TASKS:
      return {
        tasks: payload,
        lengthArrayTasks: parseInt(action.headers['x-pagination-total-count'])
      };
    default:
      return state;
  }
};

const rootReducer = combineReducers({ isRunningTimer });

export default rootReducer;

应用程序

class App extends Component {
  constructor() {
    super();
    this.state = {
      name: 'React'
    };
  }

  componentDidMount() {
    this.props.runningTimer();
  }

  render() {
    return (
      <div>

      </div>
    );
  }
}

const mapStateToProps = state => {
  const { isRunningTimer } = state;

  return {
    isRunningTimer
  };
};

const mapDispatchToProps = dispatch => ({
  runningTimer: (userId, query, statusTask, pageNumber) => dispatch(runningTimer()),
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);
3个回答

1 考虑你的状态设计。

我发现考虑状态对象在给定时间点的样子很有用。

这是我的应用程序中使用的初始状态示例。

const initialState = {
        grocers: null,
        coords: {
            latitude: 37.785,
            longitude: -122.406
        }

    };

这是在 createStore 中注入的。

分解您的应用程序状态对象/属性,也应该有助于使您的操作更简单。

2号

考虑分解你的行为。

我的想法,解耦动作代码, 在 .then 在第二个 .then .(考虑将结果保存在用户的某处:对象)

        .then(response => {
          const data = response.data.user;
          setUsers(data);})
        .catch(error => {
            console.log('There has been a problem with your fetch operation: ' + error.message);
        })

    function setUsers(data){
        dispatch({
            type: FETCH_USERS,
            payload: data
        });
    }

这是指SOLID设计原则中的S。单一职责原则。

https://devopedia.org/solid-design-principles

3号

如果“getUser”信息获取失败,请考虑这一点。

将进程/响应分开将允许更干净地调试应用程序。例如,用户 api 失败或 getTask api 失败等。


有关 redux 的更多资源。 https://redux.js.org/introduction/learning-resources#thinking-in-redux

扩展@Cullen 之前的回答,这就是我所做的:

  1. 由于您已经对 GET_TODOS 进行了操作,因此只需让操作创建者runningTimer做一件事并且只做一件事 - 调用 API/api/v1/beta/<userId>并分派相应的操作。
export const runningTimer = (
  userId,
  query,
  statusTask,
  pageNumber
) => dispatch => {
  return axios({
    url: `/api/v1/beta/${userId}`,
    method: "GET"
  })
    .then(({ data }) => {
      dispatch({
        type: RUNNING_TIMER,
        payload: data
      });
    })
    .catch(error => {
      console.log(error);

      dispatch({ type: FETCH_FAILURE });
    });
};

  1. 更新应用组件的 props 以读取存储数据。
...
const mapStateToProps = state => {
  const { isRunningTimer, todos, todo } = state;

  return {
    todos,
    todo,
    isRunningTimer,
  };
};

const mapDispatchToProps = dispatch => ({
  getTodos: () => dispatch(getTodos()),
  getTodo: id => dispatch(getTodo(id)),
  runningTimer: (userId, query, statusTask, pageNumber) => dispatch(runningTimer(userId)),
});
...
  1. 更新componentDidMountto dispatch的实现isRunningTimer-
componentDidMount() {
...
    // call with userId 1
    this.props.runningTimer(1).then(() => {
      console.log(this.props);

          // additional params for getTasks
      const params = {
        sort: 'name'
      };

      // another call for getTodos with names sorted
      this.props.getTodos(params);
    });
...

注意:您需要更新您的getTodos操作以接收可选params参数(如果未通过则将其初始化为空对象)。

希望这对你有帮助。

此处提供了用于此的实时沙箱 - https://stackblitz.com/edit/react-redux-more-actions

查看React-boilerplatereact和还原的伟大样板。他们也使用redux-sagaredux-hooks