每个React组件仅获取一次数据

时间:2018-10-22 12:29:13

标签: javascript reactjs

我有一个简单的组件,可以提取数据,然后才显示它:

class MyComponent extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            loaded: false
            stuff: null
        };
    }

    componentDidMount() {
        // load stuff
        fetch( { path: '/load/stuff' } ).then( stuff => {
            this.setState({
                loaded: true,
                stuff: stuff
            });
        } );
    }

    render() {
        if ( !this.state.loaded ) {
            // not loaded yet
            return false;
        }

        // display component based on loaded stuff
        return (
            <SomeControl>
                { this.state.stuff.map( ( item, index ) =>
                    <h1>items with stuff</h1>
                ) }
            </SomeControl>
        );
    }
}

MyComponent的每个实例都从相同的URL加载相同的数据,我需要以某种方式存储它,以避免对服务器的重复请求。

例如,如果我的页面上有10个MyComponent-应该只有一个请求(提取1个)。

我的问题是存储此类数据的正确方法是什么?我应该使用静态变量吗?还是我需要使用两个不同的组件?

感谢您的咨询!

6 个答案:

答案 0 :(得分:2)

您应该考虑使用状态管理库(例如redux),在那里您可以存储所有应用程序状态以及需要数据的组件可以预订。您可以仅在应用程序的根组件中调用一次获取,并且组件的所有10个实例都可以订阅状态。

答案 1 :(得分:1)

如果要仅使用react模拟单个提取调用。然后,您可以从react context API中使用提供方使用者API。在那里,您只能在provider中进行一次api调用,并且可以使用组件中的数据。

const YourContext = React.createContext({});//instead of blacnk object you can have array also depending on your data type of response
const { Provider, Consumer } = YourContext
class ProviderComponent extends React.Component {
   componentDidMount() {
     //make your api call here and and set the value in state
      fetch("your/url").then((res) => {
         this.setState({
           value: res,
         })
       })

   }
   render()  {
     <Provider value={this.state.value}>
       {this.props.children}
     </Provider>
   }
}

export {
 Provider,
 Consumer,
}

At some top level you can wrap your Page component inside Provider. Like this
<Provider>
   <YourParentComponent /> 
</Provider>

In your components where you want to use your data. You can something like this kind of setup

import { Consumer } from "path to the file having definition of provider and consumer"

<Consumer>
{stuff => <SomeControl>
                { stuff.map( ( item, index ) =>
                    <h1>items with stuff</h1>
                ) }
            </SomeControl>
}
</Consumer>

更方便的方法是使用某种状态管理器,例如redux或mobx。您也可以探索这些选项。您可以在这里阅读有关上下文的信息 link to context react website

  

注意:这是伪代码。有关确切的实现,请参考链接   上面提到的

答案 2 :(得分:1)

如果您想避免使用redux或某种状态管理库,则可以导入一个文件来为您进行提取。遵循这些原则。本质上,缓存存储在fetcher.js文件中。导入文件时,实际上并不是每次都将其导入为单独的代码,因此缓存变量在两次导入之间是一致的。在第一个请求上,将缓存设置为Promise;在后续请求中,承诺仅会返回。

Flux<T>

答案 3 :(得分:1)

您可以使用类似以下代码的方式将活动请求合并为一个承诺:

const f = (cache) => (o) => {
    const cached = cache.get(o.path);
    if (cached) {
        return cached;
    }
    const p = fetch(o.path).then((result) => {
        cache.delete(o.path);
        return result;
    });
    cache.set(o.path, p);
    return p;
};
export default f(new Map());//use Map as caching

答案 4 :(得分:1)

如果您的用例建议您在页面上可能包含10个组件,那么我认为您的第二个选择就是答案-两个组件。一个组件用于获取数据并基于数据呈现子级,第二个组件用于接收数据并呈现数据。

这是“智能”和“哑巴”组件的基础。智能组件知道如何获取数据并使用这些数据执行操作,而哑组件只是简单地渲染提供给它们的数据。在我看来,您上面指定的组件本身就太聪明了。

答案 5 :(得分:0)

适用于试图使用功能组件解决问题的人。

如果您只想获取装载时的数据,则可以将一个空数组作为属性添加到useEffect

应该是:

useEffect( () => { yourFetch and set }, []) //Empty array for deps.