[英]React-Redux + Redux-Thunk on functional component. Update UI after data is fetched from API
[英]React Functional Component, Redux and Loading Data
我目前正在嘗試獲取功能性反應,並且很難找出在頁面加載時從 API 加載數據的適當方法。 我正在使用反應,redux 和 thunk。 我已經修改了我從本課程創建的項目。 我的代碼目前看起來像這樣
store.js
import {createStore, applyMiddleware, compose} from "redux";
import rootReducer from "./reducers";
import reduxImmutableStateInvariant from 'redux-immutable-state-invariant';
import thunk from "redux-thunk";
export default function configureStoreDev(initialState){
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // add support for redux dev tools
return createStore(
rootReducer,
initialState,
composeEnhancers(applyMiddleware(thunk, reduxImmutableStateInvariant()))
);
}
作者Api.js
import { handleResponse, handleError } from "./apiUtils";
const baseUrl = process.env.API_URL + "/authors/";
export function getAuthors() {
return fetch(baseUrl)
.then(handleResponse)
.catch(handleError);
}
作者Actions.js
import * as actionTypes from "./actionTypes";
import * as authorApi from "../../api/authorApi";
import {apiCallError, beginApiCall} from "./apiStatusAction";
export function loadAuthorsSuccess(authors){
return {type: actionTypes.LOAD_AUTHORS_SUCCESS, authors: authors};
}
export function loadAuthors(){
return function(dispatch){
// invoke loader
dispatch(beginApiCall());
return authorApi.getAuthors().then(response => {
dispatch(loadAuthorsSuccess(response.authors));
}).catch(error => {
dispatch(apiCallError());
throw error;
})
}
}
作者Reducer.js
import * as actionTypes from "../actions/actionTypes";
import initialState from "./initialState";
export default function authorReducer(state = initialState.authors, action){
switch(action.type){
case actionTypes.LOAD_AUTHORS_SUCCESS:
return action.authors;
default:
return state;
}
}
AuthorsPage.js
import React, {useState, useEffect} from 'react';
import {connect} from 'react-redux';
import AuthorsList from "./AuthorsList";
import Spinner from "../common/Spinner";
import {loadAuthors} from "../../redux/actions/authorActions";
import {loadCourses} from "../../redux/actions/courseActions";
function AuthorsPage({loadAuthors, deleteAuthor, loadCourses, ...props}) {
const [authors, setAuthors] = useState([...props.authors]);
const [courses, setCourses] = useState([...props.courses]);
const [loading, setLoading] = useState(props.loading);
const [redirectToAddAuthorPage, setRedirectToAddAuthorPage] = useState(false);
useEffect(() => {
loadAuthors().catch(error => {
console.log("Loading authors failed: " + error);
});
loadCourses().catch(error => {
console.log("Loading courses failed: " + error);
});
}, []);
useEffect(() => {
if(authors !== props.authors && props.authors.length > 0){
setAuthors([...props.authors]);
}
}, [props.authors]);
useEffect(() => {
setLoading(props.loading)
}, [props.loading]);
return (
<>
<h2>Authors</h2>
{loading === true ? <Spinner/> : (
<>
<button
style={{ marginBottom: 20 }}
className="btn btn-primary add-course"
onClick={() => setRedirectToAddAuthorPage(true )}
>
Add Author
</button>
<AuthorsList authors={authors} />
</>
)}
</>
);
}
function mapStateToProps(state){
return {
authors: state.authors,
courses: state.courses,
loading: state.apiCallsInProgress > 0
}
}
const mapDispatchToProps = {
loadAuthors: loadAuthors,
loadCourses: loadCourses
}
export default connect(mapStateToProps, mapDispatchToProps)(AuthorsPage);
我遇到問題的部分是讓作者列表正確設置 state。 我嘗試在調用loadAuthors()
之后設置它,但沒有在該調用的 .then( .then()
中返回作者列表。
下一個選項是使用useEffect
監聽作者的 props 變化,但這似乎不是加載我在初始加載時需要的數據的最有效或正確的方法。
我似乎無法找到任何文章或教程,詳細說明從功能組件的角度完成此任務的適當方法,並且希望在正確方向上提供任何指導或指示。
下一個選項是使用 useEffect 監聽作者的 props 變化,但這似乎不是加載我在初始加載時需要的數據的最有效或正確的方法。
您可以直接渲染props.authors
而無需將其分配給useState
例子
const thunk = ReduxThunk.default; const { connect, Provider } = ReactRedux; const { bindActionCreators, combineReducers, createStore, applyMiddleware } = Redux; window.redux = Redux; const initialState = { authors: [] }; const getAuthors = () => Promise.resolve(Array(10).fill(0).map((pr, index) => ({id: index, name: `Author ${index + 1}`}))) const loadAuthorsSuccess = (authors) => { return {type: 'LOAD_AUTHORS_SUCCESS', authors}; } const loadAuthors = () => { return function(dispatch) { return getAuthors().then(authors => { dispatch(loadAuthorsSuccess(authors)); }) } } const authorReducer = (state = initialState.authors, action) => { switch(action.type) { case 'LOAD_AUTHORS_SUCCESS': return action.authors; default: return state; } } const reducer = combineReducers({ authors: authorReducer}) const store = createStore( reducer, initialState, applyMiddleware(thunk) ); const { useState, useEffect } = React; function mapStateToProps({authors}) { return { authors } } const mapDispatchToProps = { loadAuthors } const _AuthorsPage = ({loadAuthors, authors}) => { useEffect(() => { loadAuthors().catch(error => { console.log("Loading authors failed: " + error); }); }, []) return <div> {authors.map(({id, name}) => <div key={id}>{name}</div>)} </div> } const AuthorsPage = connect(mapStateToProps, mapDispatchToProps)(_AuthorsPage) const App = () => { return <div> <AuthorsPage/> </div> } ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );
<script src="https://unpkg.com/react/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script src="https://unpkg.com/redux@4.0.5/dist/redux.js"></script> <script src="https://unpkg.com/react-redux@latest/dist/react-redux.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux-thunk/2.3.0/redux-thunk.js"></script> <div id="root"></div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.