【问题标题】:When API post is successful, dispatch a get request - React/Redux当 API 发布成功时,发送一个 get 请求 - React/Redux
【发布时间】:2019-11-29 12:26:46
【问题描述】:

我有一个小应用程序,它显示一个列表组件 (JobsList) 和另一个包含文本字段和提交按钮 (CreateJob) 的组件。虽然我能够使用 API 数据(通过 Redux)填充 JobsList,但我不确定如何在 CreateJob 中成功发布新工作后使用新的 API 调用更新 JobsList。这是我到目前为止的代码:

JobsList.js

import React, { Fragment, useEffect } from 'react';
import { connect } from 'react-redux';
import JobCard from './JobCard';
import CreateJob from './CreateJob';
import api from './Api';
import { JOBS_LOADED } from './ActionTypes';

const JobsList = ({ jobs, onLoad }) => {

useEffect(() => {
    const fetchJobs = async () => {

        try {
            const data = await api.Jobs.getAll();
            onLoad({ data });
        } catch (err) {
            console.error(err);
        }
    };
    fetchJobs();
}, [onLoad]);

return (
    <Fragment>
        <CreateJob />
        {teams.map(job => (
            <JobCard job={job} key={team.jobId} />
        ))}
    </Fragment>
);
}

const mapStateToProps = state => ({
    jobs: state.jobsReducer.teams
});

const mapDispatchToProps = dispatch => ({
    onLoad: payload =>
        dispatch({ type: JOBS_LOADED, payload }),
});

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

CreateJob.js

import React, { useState } from 'react';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import api from './Api';

const CreateJob = () => {
const [state, setState] = React.useState({
    jobName: '',
    creator: ''
});

const handleInputChange = event => {
    setState({
        ...state,
        [event.target.name]: event.target.value
    });
    // validation stuff
}

const handleSubmit = async e => {
    api.Jobs.create({state})
    try {
        await request;
        // Reload the Jobs list so it does an another API request to get all new data
        // DO I CALL A DISPATCH HERE?????
    } catch (err) {
        console.error(err);
    }
}

return (
    <div>
        <TextField
            name="jobName"
            value={state.jobName || ''}
            onChange={handleInputChange}
        />
        <Button onClick={handleSubmit}>Create job</Button>
    </div>
);
}

export default CreateJob;

JobsReducer.js

import { TEAMS_LOADED } from './ActionTypes';

export default (state = {teams: []}, action) => {
switch (action.type) {
    case TEAMS_LOADED:
        return {
            ...state,
            teams: action.payload.data,
        };
    default:
        return state;
}
};

CreateJob.jshandleSubmit 的成功结果中,如何触发/调度新的API 调用以从CreateJob.js 更新JobsList?我是 react/redux 的新手,因此对任何糟糕的代码表示歉意。非常感谢对学习者的任何建议。

【问题讨论】:

  • 我建议使用 useEffect 参数来重新触发集合长度变化
  • 感谢您的回复。你能提供更多信息吗?如何告诉不同组件中的 useEffect 再次调用?

标签: reactjs redux


【解决方案1】:

采用的简化解决方案是将用于获取作业的函数包装为 JobsList 中的变量,并将其作为道具分配给 CreateJob。然后在 CreateJob 中,由您来更新工作列表。

这个解决方案的不足之处在于它没有尽可能多地利用 redux。最好在 JobsReducer.js 中为共享操作(fetch_jobs)创建操作创建器,并将这些操作作为道具映射到需要它的组件。

JobsReducer.js

export const fetchJobsAsync = {
  return dispatch => {
    try {
      const data = await api.Jobs.getAll();
      dispatch({type: TEAMS_LOADED, payload: {data}})
    } catch (err) {
      console.error(err);
    }
  }
}

提示:您必须安装redux-thunk 才能启用异步操作。

之后,您将能够通过调度操作而不是直接调用 API 来触发 API 以从任何组件更新作业(或团队)。

JobsList.jsx 或 CreateJob.js

const mapDispatchToProps = dispatch => ({
  fetchAll: () => dispatch(fetchJobsAsync())
})

在 CreateJob.js 结束时,和调用其他常规函数一样调用 fetchAll 重新加载作业列表是完全一样的。

而且,如果您可以更进一步,请将创建新作业的 API 调用移动到 reducer 并将其包装为一个操作。在其中,如果满足预期条件(如果创建新作业成功完成),则调度 fetchJobsAsync。然后你会得到一个更清晰的组件树,只有同步道具,没有关于何时/如何重新加载作业列表的数据逻辑。

【讨论】:

  • 感谢您的回答 - 我决定接受建议并研究 Thunk - 效果很好。我发现这篇文章让我启动并运行 - medium.com/@stowball/…
  • @Josethehose 不客气。很高兴听到我的回答很有帮助。
【解决方案2】:

是的,你的方法绝对正确。

一旦你发布了一份新工作,你可以根据它的回复触发fetchJobs,你可以将它作为道具传递给&lt;CreateJob fetchJobs={fetchJobs}/&gt;

为此,您必须像这样在 useEffect() 之外声明它:

import React, { Fragment, useEffect } from 'react';
import { connect } from 'react-redux';
import JobCard from './JobCard';
import CreateJob from './CreateJob';
import api from './Api';
import { JOBS_LOADED } from './ActionTypes';

const JobsList = ({ jobs, onLoad }) => {

const fetchJobs = async () => {
  try {
    const data = await api.Jobs.getAll();
    onLoad({ data });
  } catch (err) {
    console.error(err);
  }
};

useEffect(() => {
  fetchJobs();
}, [onLoad]);

return (
  <Fragment>
    <CreateJob fetchJobs={fetchJobs}/>
    {teams.map(job => (
      <JobCard job={job} key={team.jobId} />
    ))}
  </Fragment>
  );
}

const mapStateToProps = state => ({
  jobs: state.jobsReducer.teams
});

const mapDispatchToProps = dispatch => ({
  onLoad: payload =>
  dispatch({ type: JOBS_LOADED, payload }),
});

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

一旦触发 api 调用,新数据将以 redux 状态加载:

import React, { useState } from 'react';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import api from './Api';

const CreateJob = props => {
const [state, setState] = React.useState({
    jobName: '',
    creator: ''
});

const handleInputChange = event => {
    setState({
        ...state,
        [event.target.name]: event.target.value
    });
    // validation stuff
}

const handleSubmit = async e => {
    api.Jobs.create({state})
    try {
        await request;
        props.fetchJobs()
    } catch (err) {
        console.error(err);
    }
}

return (
    <div>
        <TextField
            name="jobName"
            value={state.jobName || ''}
            onChange={handleInputChange}
        />
        <Button onClick={handleSubmit}>Create job</Button>
    </div>
);
}

export default CreateJob;

由于 JobsList 组件已订阅状态并在此处接受 state.jobsReducer.teams 作为道具:

const mapStateToProps = state => ({
    jobs: state.jobsReducer.teams
});

&lt;CreateJobs /&gt; 加载新作业时,道具会发生变化,道具的这种变化将导致 &lt;JobsLists /&gt; 使用新道具重新渲染。

【讨论】:

  • 非常感谢您的回答。我认为对我来说更好的方法是使用 Thunk。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 2011-03-13
  • 2018-03-18
相关资源
最近更新 更多