在 axios 中通过 id 连接来自不同 api 的两个 json objects 获取并存储

concat two json objects from different api by id in axios get and store

我有一个关于如何在 axios 中添加第二个嵌套 api 查询的问题。第二个 api 查询根据第一个 api 数组 json 中的 id 获取 json object。然后在函数 Retrieve()?

中连接到全局数组

先api url:

'/api/sets'

秒apichildren:

'/api/sets/' + todo.id + '/tasks'

响应全局 json 来自第一个 api url:

[
    {
        "id": 121,
        "name": "list1",
        "description": "description1"
    },
    {
        "id": 9,
        "name": "list2",
        "description": "description2"
    }
]

响应第二个 json children 来自 api 第一个 api:

[
    {
        "id": 1,
        "name": "task1",
        "description": "description task1"
    },
    {
        "id": 2,
        "name": "task2",
        "description": "description task2"
    }
]

最后预期组合存储数组json

[
     {
        "id": 121,
        "name": "list1",
        "description": "description1",
        "task": [{
                "id": 1,
                "name": "task1",
                "description": "description task1"
            },
            {
                "id": 2,
                "name": "task2",
                "description": "description task2"
            }
        ]
    },
    {
        "id": 9,
        "name": "list2",
        "description": "description2",
        "task": [{
                "id": 10,
                "name": "task1",
                "description": "description task1"
            },
            {
                "id": 11,
                "name": "task2",
                "description": "description task2"
            }
        ]
    }
]

代码js: index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'mobx-react';
import TodoStore from './store';

const Root = (
    <Provider TodoStore={TodoStore}>
        <App />
    </Provider>
);

ReactDOM.render(Root, document.getElementById('root'));

store.js

import React from 'react';
import { observable, action, configure, runInAction } from 'mobx';
import axios from 'axios';
configure({ enforceActions: 'observed' });

class TodoStore {
    @observable todos = [];

    @action Retrieve = () => {
        axios
            .get('/api/sets')
            .then(response => {
                let tempTodos = response.data;
                runInAction(() => {
                    this.todos = tempTodos;
                });
            })
            .catch(error => {
                console.log(error);
            });
    };
}

const store = new TodoStore();
export default store;

如果您 API 不支持 GraphQL 端点,那么您应该扩展 Retrive() 操作并对集合 ID 执行额外的 XHR 请求以合并来自 API 端点 1 和 2 的结果.

 @action Retrieve = () => {
        axios
            .get('/api/sets')
            .then(response => {
                let tempTodos = response.data;

                let todosWithTasks = tempTodos.map(todo => {

                   let tasks = null;

                    axios.get('/api/sets/' + todo.id + '/tasks')
                      .then(response2 => {
                          tasks = response2.data;
                      }).catch(error => {
                          console.log(error);
                      });

                    todo.task = tasks;
                    return todo;

                });

                // `todosWithTasks` is joined API1 and API2

            })
            .catch(error => {
                console.log(error);
            });
    };

感谢成功,所有api都加入了,现在我又遇到了一个小问题。如果在控制台日志中设置 @observable.ref todos = [];@observable.shallow todos = [];task 退出对象数组,但是当我设置 @observable todos = [];task 不存在。

console.log

(2) [{…}, {…}]
  0:
    description: "false"
    id: 121
    name: "list1"
    task: Array(2)
      0: {id: 10, name: "task1", description: "description task1", state: false, position: 1}
      1: {id: 11, name: "task2", description: "description task2", state: true position: 2}
      length: 2
      __proto__: Array(0)
  __proto__: Object
  1:
    description: "false"
    id: 9
    name: "list2"
    task: Array(2)
      0: {id: 3, name: "task1", description: "description task1", state: false, position: 3}
      1: {id: 7, name: "task2", description: "description task2", state: false, position: 5}
      length: 2
      __proto__: Array(0)
  __proto__: Object
  length: 2
  __proto__: Array(0)

如果尝试映射键 task

index.module.js:206 Uncaught TypeError: Cannot read property 'map' of undefined
    at eval (TodoItem.jsx:17)
    at eval (index.module.js:220)
    at eval (index.module.js:198)
    at trackDerivedFunction (mobx.module.js:1212)
    at Reaction.track (mobx.module.js:1752)
    at useObserver (index.module.js:196)
    at wrappedComponent (index.module.js:220)
    at renderWithHooks (react-dom.development.js:12938)
    at updateFunctionComponent (react-dom.development.js:14627)
    at updateSimpleMemoComponent (react-dom.development.js:14573)

react-dom.development.js:17117 The above error occurred in the <wrappedComponent> component:
    in wrappedComponent (created by n)
    in n (created by inject-with-TodoStore(Object))
    in inject-with-TodoStore(Object) (created by App)
    in div (created by App)
    in App (created by n)
    in n (created by inject-with-TodoStore(App))
    in inject-with-TodoStore(App)
    in e

code index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import { Provider } from 'mobx-react';
import TodoStore from './TodoStore';
import registerServiceWorker from './registerServiceWorker';

const Root = (
    <Provider TodoStore={TodoStore}>
        <App />
    </Provider>
);

ReactDOM.render(Root, document.getElementById('root'));
registerServiceWorker();

TodoStore.js

import React from 'react';
import {observable, action, computed, configure, runInAction} from 'mobx';
import axios from 'axios';
axios.defaults.baseURL = 'api';
configure({ enforceActions: 'observed' });

class TodoStore {
    @observable.shallow todos = [];

    @action Retrieve = () => {
        axios
            .get('/sets')
            .then(response => {
                let tempTodos = response.data;

                let todosWithTasks = tempTodos.map(todo => {
                    let tasks = null;

                    axios
                        .get('/sets/' + todo.id + '/tasks')
                        .then(response2 => {
                            todo.task = response2.data;
                        })
                        .catch(error => {
                            console.log(error);
                        });
                    return todo;
                });
                runInAction(() => {
                    this.todos = todosWithTasks;
                });
            })
            .catch(error => {
                console.log(error);
            });
    };
}

const store = new TodoStore();
export default store;

app.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import TodoItem from './TodoItem';
import { toJS } from 'mobx';
import { inject, observer } from 'mobx-react';

@inject('TodoStore')
@observer
class App extends Component {
    render() {
        const TodoStore = this.props.TodoStore;
        console.log(toJS(TodoStore.todos));

        return (
            <div className="App">
                {TodoStore.todos.map(todo => (
                    <TodoItem key={todo.id} todo={todo} />
                ))}
            </div>
        );
    }

    async componentDidMount() {
        this.props.TodoStore.Retrieve();
    }
}
TodoItem.wrappedComponent.propTypes = {
    todo: PropTypes.object.isRequired,
    TodoStore: PropTypes.object.isRequired
};
export default App;

todoitem

import React from 'react';
import PropTypes from 'prop-types';
import { inject, observer } from 'mobx-react';
import TodoItemTask from './TodoItemtask';

const TodoItem = inject('TodoStore')(
    observer(props => {
        const TodoStore = props.TodoStore;

        return (
            <>
                <div key={props.todo.id} className="todo-item">
                    <span>{props.todo.id}</span>
                    <h5>{props.todo.name}</h5>
                    <p>{props.todo.description}</p>

                    {props.todo.task.map((item, index) => (
                        <TodoItemTask key={index + item.id} item={item} />
                    ))}
                </div>
            </>
        );
    })
);

TodoItem.wrappedComponent.propTypes = {
    todo: PropTypes.object.isRequired,
    TodoStore: PropTypes.object.isRequired
};

export default TodoItem;

TodoItemTask.js

import React from 'react';
import PropTypes from 'prop-types';
import { inject, observer } from 'mobx-react';

const TodoItemTask = inject('TodoStore')(
    observer(props => {
        const TodoStore = props.TodoStore;

        return (
            <>
                <div key={props.item.id} className="todo-item">
                    <span>{props.index}</span>
                    <p>{props.item.name}</p>
                    <p>{props.item.description}</p>
                </div>
            </>
        );
    })
);

TodoItemTask.wrappedComponent.propTypes = {
    item: PropTypes.object.isRequired,
    TodoStore: PropTypes.object.isRequired
};

export default TodoItemTask;

如果设置静态数据则没有错误并呈现所有数据

@observable todos = [
     {
        "id": 121,
        "name": "list1",
        "description": "description1",
        "task": [{
                "id": 1,
                "name": "task1",
                "description": "description task1"
            },
            {
                "id": 2,
                "name": "task2",
                "description": "description task2"
            }
        ]
    },
    {
        "id": 9,
        "name": "list2",
        "description": "description2",
        "task": [{
                "id": 10,
                "name": "task1",
                "description": "description task1"
            },
            {
                "id": 11,
                "name": "task2",
                "description": "description task2"
            }
        ]
    }
];

其实这不是mobx的问题,我发现两个api url json在这个函数中连接错误。 在 console.log(todosWithTasks) 中看起来是正确的,但在 console.log (JSON.stringify(todosWithTasks)) 中不是。

这是实际代码

import React from 'react';
import {observable, action, computed, configure, runInAction} from 'mobx';
import axios from 'axios';
axios.defaults.baseURL = 'api';
configure({ enforceActions: 'observed' });

class TodoStore {
    @observable todos = [];

@action async Retrieve = () => {
    this.isLoading = true;
    await axios
        .get('/sets')
        .then(async response => {
            let tempTodos = response.data;
            tempTodos.forEach(todo => (todo.task = []));
            let todosWithTasks = tempTodos.map(todo => {
                axios
                    .get('/sets/' + todo.id + '/tasks')
                    .then(response2 => {
                        todo.task = response2.data;
                        return todo;
                    })
                    .catch(error => {
                        console.log(error);
                    });
                return todo;
            });
            runInAction(() => {
                console.log(todosWithTasks);
                console.log(JSON.stringify(todosWithTasks));
                this.todos = todosWithTasks;
            });
        })
        .catch(error => {
            console.log(error);
        });
   };

}

const store = new TodoStore();
export default store;

console.log(JSON.stringify(todosWithTasks))

的输出
[{"id":1,"name":"list1","description":"description1","task":[]}]

console.log(todosWithTasks) 的输出看起来不错

(1) [{…}]
    0:
        description: "description1"
        id: 1
        name: "list1"
        task: Array(1)
            0: {id: 1, name: "task1", description: "description task1"}
            length: 1
            __proto__: Array(0)
        __proto__: Object
    length: 1
    __proto__: Array(0)

因此,它不会在地图函数中呈现,因为 key task 是空的。

如果本地修改合并json文件,在axios中一切正常。在 console.log (JSON.stringify (todosWithTasks)) 一切正常。

    @action Retrieve() {
        axios
            .get('localhost:3000/src/data.json')
            .then(response => {
                let tempTodos = response.data;
                tempTodos.forEach(todo => (todo.editing = false));

                runInAction(() => {
                    this.todos = tempTodos;
                    console.log(JSON.stringify(tempTodos));
                });
            })
            .catch(error => {
                console.log(error);
            });
    }