简体   繁体   English

React 功能组件,Redux 和加载数据

[英]React Functional Component, Redux and Loading Data

I am currently trying to pick up functional react and am having a tough time figuring out the appropriate way to load data from an API on page load.我目前正在尝试获取功能性反应,并且很难找出在页面加载时从 API 加载数据的适当方法。 I am using react, redux and thunks.我正在使用反应,redux 和 thunk。 I have modified the project that i created from this course .我已经修改了我从本课程创建的项目。 My code currently looks like this我的代码目前看起来像这样

store.js 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()))
    );
}

authorApi.js作者Api.js

import { handleResponse, handleError } from "./apiUtils";
const baseUrl = process.env.API_URL + "/authors/";

export function getAuthors() {
  return fetch(baseUrl)
    .then(handleResponse)
    .catch(handleError);
}

authorActions.js作者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;
        })
    }
}

authorReducer.js作者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 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);

The part that i am having trouble with is getting the state for the authors list to set appropriately.我遇到问题的部分是让作者列表正确设置 state。 I tried setting it after the call to loadAuthors() but am not getting the authors list returned in the .then() of that call.我尝试在调用loadAuthors()之后设置它,但没有在该调用的 .then( .then()中返回作者列表。

The next option was to listen for the author props to change with useEffect but this doesn't seem to be the most efficient or correct way of loading the data that i need on the initial load.下一个选项是使用useEffect监听作者的 props 变化,但这似乎不是加载我在初始加载时需要的数据的最有效或正确的方法。

I cant seem to find any articles or tutorials detailing the appropriate method to accomplish this from a functional component perspective and would appreciate any guidance or pointers in the right direction.我似乎无法找到任何文章或教程,详细说明从功能组件的角度完成此任务的适当方法,并且希望在正确方向上提供任何指导或指示。

The next option was to listen for the author props to change with useEffect but this doesn't seem to be the most efficient or correct way of loading the data that i need on the initial load.下一个选项是使用 useEffect 监听作者的 props 变化,但这似乎不是加载我在初始加载时需要的数据的最有效或正确的方法。

You could render props.authors directly without assigning it to useState您可以直接渲染props.authors而无需将其分配给useState

Example例子

 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM