Cannot update a component from inside the function body of a different component

Viewed 2806

In reactJS, I want to create a function that will be in charge of loading data.

The call of this function is done within the Controller, children of my component.

I also want to recall the loadData function from the Controller when state.perPage and state.page change.

I have switch from class component to function component but the error remain:

Cannot update a component from inside the function body of a different component

This is my component:

const MyPromotionsController = (props) => {
  const {
    children,
    fetchSuccess,
    t,
    loadingComponent: LoadingComponent,
    pagination: initialPagination,
    sort,
    filter,
    ...rest // eslint-disable-line no-unused-vars
  } = omit(props, [
    'setLocale',
    'locale',
  ]);
  const dataProvider = useDataProvider();
  const [pagination, setPagination] = useState(initialPagination);

  const _loadData = () => {
    const params = {
      pagination,
      sort,
      filter,
    };
    return dataProvider
      .getList('merchants/promotions', params);
  };

  return (
    <Controller
      pagination={pagination}
      FetchStart={LoadingComponent}
      FetchError={TranslatedFetchError}
      loadData={_loadData}
      onFetchSuccess={fetchSuccess}
      fetchStartMessages={{
        fetching: 'promotionsController.fetchStart.fetching',
      }}
      fetchErrorMessages={{
        error: 'promotionsController.fetchError.error',
      }}
    >
      {cloneElement(children, {
        pagination,
        setPagination,
      })}
    </Controller>
  );
};

I have tried to use useEffect like this but now the function never get called:

const MyPromotionsController = (props) => {
  const {
    children,
    fetchSuccess,
    t,
    loadingComponent: LoadingComponent,
    pagination: initialPagination,
    sort,
    filter,
    ...rest // eslint-disable-line no-unused-vars
  } = omit(props, [
    'setLocale',
    'locale',
  ]);
  const dataProvider = useDataProvider();
  const [pagination, setPagination] = useState(initialPagination);

  let _loadData = () => {};
  useEffect(() => {
    _loadData = () => {
      const params = {
        pagination,
        sort,
        filter,
      };
      return dataProvider
        .getList('merchants/promotions', params);
    };
  }, [pagination]);

  return (
    <Controller
      pagination={pagination}
      FetchStart={LoadingComponent}
      FetchError={TranslatedFetchError}
      loadData={_loadData}
      onFetchSuccess={fetchSuccess}
      fetchStartMessages={{
        fetching: 'promotionsController.fetchStart.fetching',
      }}
      fetchErrorMessages={{
        error: 'promotionsController.fetchError.error',
      }}
    >
      {cloneElement(children, {
        pagination,
        setPagination,
      })}
    </Controller>
  );
};

This is the controller:

class Controller extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: 0,
      data: null,
      error: null,
    };
  }

  async componentDidMount() {
    await this.refreshData();
  }

  async UNSAFE_componentWillReceiveProps(nextProps) {
    if (JSON.stringify(this.props.pagination) !== JSON.stringify(nextProps.pagination)) {
      console.log(nextProps);
      await this.refreshData();
    }
  }

  refreshData = async () => {
    const {
      loadData,
      onFetchStart,
      onFetchSuccess,
      onFetchError,
      fetchStart,
      fetchSuccess,
      fetchError,
      fetchErrorMessages: { error: errorMessage },
      t,
    } = this.props;
    this.setState({
      loading: 1,
    });
    try {
      fetchStart();
      if (onFetchStart) {
        onFetchStart();
      }
      const data = await loadData();
      this.setState({
        data,
        loading: 0,
        error: null,
      });
      fetchSuccess(data);
      if (onFetchSuccess) {
        onFetchSuccess(data);
      }
    } catch (e) {
      console.log(e);
      const error = new Error(t(errorMessage));
      fetchError(error);
      this.setState({
        data: null,
        loading: 0,
        error,
      });
      if (onFetchError) {
        onFetchError(new Error(t(errorMessage)));
      }
    }
  };

  render() {
    const {
      children,
      fetchStartMessages,
      fetchErrorMessages,
      FetchStart,
      FetchError,
      ...rest
    } = omit(this.props, [
      'onFetchSuccess',
      'onFetchStart',
      'onFetchError',
      'fetchSuccess',
      'fetchStart',
      'fetchError',
      't',
      'setLocale',
      'locale',
    ]);
    const { loading, data, error } = this.state;

    if (!error && !data && FetchStart) {
      return (
        <FetchStart
          messages={fetchStartMessages}
        />
      );
    }
    if (error && FetchError) {
      return (
        <FetchError
          loading={loading}
          error={error}
          onPress={this.refreshData}
          messages={fetchErrorMessages}
        />
      );
    }

    return cloneElement(children, {
      ...rest,
      data,
      error,
      loading,
      refreshData: this.refreshData,
    });
  }
}

How can I fix those warnings ?

0 Answers
Related