简体   繁体   中英

How to Refactor an Async Function out of a React Component

I have a straightforward react component that looks so in AllWords.js :

import React, {  useEffect, useState } from 'react';
import consts from '../../constants/Constants.js';

function AllWords() {
  const [words, setWords] = useState([]);

  async function fetchData(){
    
    const response= await fetch(consts.FETCH_URL);
    const data = await (response.json());
    setWords(data);
  };

  // API:  useEffect( () => { . . . return cleanup; },[var_n_whose_change_triggers_useEffect . . .] );

  useEffect(() => {fetchData()}, [] );

    return (
    <>
    {
      words.map(w=> <div>{w.word}</div>)
    }
    </>
  );
}

export default AllWords;

I would like to refactor the fetchData() method out of the component into another file (basically a separate .js file that holds the fetch call).

What I would like is to have created a file titled FetchAllWords.js under src/actions/ & then import it. & use that.

I have several questions :

  1. do I need to set the state in the FetchAllWords.js and then useSelector to extract the state in AllWords.js ?
  2. in FetchAllWords.js do I need to usedispatch to dispatch a method call setting the state ? I would like to just setState in FetchAllWords.js and then extract it in AllWords.js . This is what I have so far:
import consts from '../constants/Constants.js';
import {  useState } from 'react';


async function FetchAllWords(){
    const [words, setWords] = useState([]);
  
        const response= await fetch(consts.FETCH_URL);
        const data = await (response.json());
        setWords(data);
    
}
 

export default FetchAllWords;

I am unsure how to import this and use it in AllWords.js . I am using the following statement : import wordList from '../../actions/FetchAllWords';

Then I am trying to use wordList as a handle to the file '../../actions/FetchAllWords.js' & attempting to access the async function FetchAllWords so wordList.FetchAllWords() ;

Firstly , the editor (VSCode) won't let me see the function despite the import call.

Secondly I am getting an error (something like) : TypeError: _actions_FetchAllWords_js__WEBPACK_IMPORTED_MODULE_3__.default.FetchAllWords is not a function

Any insight or help would be appreciated since rather uneasy with JS & React. The github repo is : https://github.com/mrarthurwhite/hooks-p5-react-redux

EDIT : As per David's suggestions :

So AllWords.js React component is :

import React, {  useEffect, useState } from 'react';
import wordList from '../../services/Fetch.js';
function AllWords() {
  const [words, setWords] = useState([]);

  function fetchData(){
    
    wordList.fetchAllWords().then(
      data =>  setWords(data)
    );
  };

  // API:  useEffect( () => { . . . return cleanup; },[var_n_whose_change_triggers_useEffect . . .] );
  useEffect(() => {fetchData()}, [] );

    return (
    <>
    {
      words.map(w=> <div>{w.word}</div>)
    }
    </>
  );
}

export default AllWords;

And Fetch.js is :

import consts from '../constants/Constants.js';

class Fetch { 

async fetchAllWords(){
        const response= await fetch(consts.FETCH_URL);
        const data = await (response.json());
        return data;
}
 
       
}
export default Fetch;

No, don't worry about state in the external file. Just focus on the one thing it should do, perform the AJAX operation. At its simplest it's just a function, something like:

import consts from '../../constants/Constants.js';

const fetchAllWords = async () => {
    const response = await fetch(consts.FETCH_URL);
    const data = await (response.json());
    return data;
}

export default fetchAllWords;

You can even make it a class which contains this function, if you plan on adding other service operations as well. (Fetch specific word? Find word? etc.) The point is that this does just one thing, provide data. Let the React components handle React state.

Within the component you'd just use that to get your data. Something like:

import React, {  useEffect, useState } from 'react';
import fetchAllWords from '../../services/FetchAllWords.js';

function AllWords() {
  const [words, setWords] = useState([]);

  useEffect(() => {
    fetchAllWords().then(w => setWords(w));
  }, []);

  return (
    <>
    {
      words.map(w=> <div>{w.word}</div>)
    }
    </>
  );
}

export default AllWords;

Overall it's a matter of separating concerns. The service performs the AJAX operation and returns the meaningful data, internally concerned with things like JSON deserialization and whatnot. The React component maintains the state and renders the output, internally concerned with updating state after useEffect runs and whatnot.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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