Calling one function in another and passing it id, react + redux

人走茶凉 提交于 2019-12-25 00:09:01

问题


In React itself, I have the function getTodos(), in which it calls another functiongetTodo(). It passes res.data[0].id to the getTodo() function.

React

Demo here: https://stackblitz.com/edit/react-qvsjrz

Code below:

class App extends Component {
  constructor() {
    super();
    this.state = {
      todos: [],
      todo: {}
    };
  }

  componentDidMount() {
    this.getTodos()
  }

  getTodos = () => {
    axios({
        url: 'https://jsonplaceholder.typicode.com/todos',
        method: 'GET'
    })
    .then(res => {
      this.setState({
        todos: res.data,
      }, () => this.getTodo(res.data[0].id))
    })  
    .catch(error => {
      console.log(error);
    });
  };

  getTodo = (todoId) => {
    axios({
      url: `https://jsonplaceholder.typicode.com/todos/${todoId}`,
      method: 'GET'
    })
    .then(res => {
      this.setState({
        todo: res.data
      })
    })
    .catch(error => {
      console.log(error);

    })
  }

  render() {
    console.log(this.state.todo);
    return (
      <div>

      </div>
    );
  }
}

The above code tries to convert to react + redux.

React + redux

In actions, I declared two functions getTodo andgetTodos. Could someone advise me on how to call the getTodo function in thegetTodos function by passing the getTodo id function?

Demo here: https://stackblitz.com/edit/react-ewpquh?file=actions%2Findex.js

actions

   import axios from 'axios';

    export const GET_TODOS = 'GET_TODOS';
    export const FETCH_SUCCESS = 'FETCH_SUCCESS';
    export const FETCH_FAILURE = 'FETCH_FAILURE';

    export const getTodos = () => 
     dispatch => {

  return axios({
      url: 'https://jsonplaceholder.typicode.com/todos',
      method: 'GET',
    })
    .then(({data})=> {
      console.log(data);

      dispatch({type: GET_TODOS, payload:{
        data 
      }});   
    })
    .catch(error => {
      console.log(error);

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

    export const getTodo = () => 
    dispatch => {


  return axios({
      url: 'https://jsonplaceholder.typicode.com/todos',
      method: 'GET',
    })
    .then(({data})=> {
      console.log(data);

      dispatch({type: GET_TODOS, payload:{
        data 
      }});   
    })
    .catch(error => {
      console.log(error);

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

Todos

import React, { Component } from 'react';
import { connect } from 'react-redux';
import {getTodos} from '../.././actions';

class Todos extends Component {
  componentDidMount() {
    this.props.getTodos(); 
  }

  render() {
    return (
      <ul>
        {this.props.todos.map(todo => {
        return <li key={todo.id}>
                  {todo.title}
               </li>
         })}
      </ul>
    );
  }
}

const mapStateToProps = state => {
  console.log(state.todos);
  const { todos } = state;

  return {
    todos
  };
};

const mapDispatchToProps = dispatch => ({
  getTodos: () => dispatch(getTodos())
});

export default connect(mapStateToProps, mapDispatchToProps)(Todos);

reducers

import {GET_TODOS} from '../../actions';

const initialState = {
  todos: []
};

const rootReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'GET_TODOS':
      return {
        ...state,
        todos: action.payload.data
      };

    default:
      return state;
  }
};

export default rootReducer;

store

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

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

export default store;

回答1:


Instead of over-complicating your actions, you should have separate action types for different APIs.

  1. GET_TODOS - For /todos API
  2. GET_TO - For /todos/ API

To add getTodo method with ID, this is how I solved it -

  1. For each li tag, add an onClick that calls your getTodo API. (This is done as an example for the sake of adding getTodo in the workflow.
    return <li key={todo.id} onClick={() => this.handleClick(todo.id)}>
  1. Add handleClick which calls getTodo method from props.
    • First add getTodo in your components mapDispatchToProps:
    import { getTodo, getTodos} from '../.././actions';

    const mapDispatchToProps = dispatch => ({
      getTodos: () => dispatch(getTodos()),
      getTodo: id => dispatch(getTodo(id))
    });
  • Add handleClick -

  handleClick = id => {
    this.props.getTodo(id).then(() => {
      console.log(`You Clicked: ${JSON.stringify(this.props.todo)}`)
    })
  }
  1. Update your getTodo action to take ID as input:

NOTE: The added GET_TODO type

export const getTodo = (id) => dispatch => {

  return axios({
      url: `https://jsonplaceholder.typicode.com/todos/${id}`,
      method: 'GET',
    })
    .then(({data})=> {
      // console.log(data);
      dispatch({type: GET_TODO, payload: data});   
    })
    .catch(error => {
      console.log(error);

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

  1. Separate out your reducers into todos and todo and use combineReducers from redux package -

const todos = (state = [], action) => {
  const { type, payload } = action;

  switch(type) {
    case 'GET_TODOS':
      return payload;
    default:
      return state;
  }
}

const todo = (state = {}, action) => {
  const { type, payload } = action;

  switch(type) {
    case 'GET_TODO':
      return payload;
    default:
      return state;
  }
}

const rootReducer = combineReducers({todos, todo});
  1. Run the app and click on any item in the todo list. Console log for the clicked todo item is shown when API response for that ID is fetched.

The live sandbox is available here - https://stackblitz.com/edit/react-ndkasm



来源:https://stackoverflow.com/questions/58214170/calling-one-function-in-another-and-passing-it-id-react-redux

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!