React JS冻结浏览器

时间:2016-01-12 16:59:12

标签: reactjs virtual-dom

我有一个具有2000个元素的React组件,并根据一些过滤条件更新我的状态,这会在内部导致重新渲染。一切似乎都很好。但是当我将2000个元素的togglefilter改为1000个元素并且返回& out时,渲染需要花费很多时间,有时浏览器会冻结。我做了镀铬时间线分析,主要耗时的部分是渲染。任何帮助将不胜感激。

enter image description here

2 个答案:

答案 0 :(得分:1)

快速解决方法是实现shouldComponentUpdate See the docs,以便渲染〜2000次子组件。

shouldComponentUpdate: function(nextProps, nextState) {
  return this.props.value !== nextProps.value;
}

另一个快速检查是问你自己是否遵循使用小型无国籍儿童的惯例,只传递道具。如果没有,可能是重构的时候了。

答案 1 :(得分:1)

@enjoylife的建议是迈出的重要一步,但是如果视图中有许多组件结构,那将很难调试,即使记住该组件也无法消除连续渲染或循环渲染。

我在遇到奇怪的冻结和奇怪的错误后才学会了这一点,无论何时用户登录首页都无法停止。想象所有屏幕。有时,您几乎不会注意到组件在重新发送。

使用控制台日志检测您的屏幕/页面(循环)重新渲染

const Home = () => {
  conso.log('home re-rending')
  // some hooks

  return <BigComponent />
}

如上所述。日志显示的时间不得超过安装组件后的限定时间。就我而言,只有一次。但是,如果太多(日志),肯定会冻结您的PC。因此,请仔细按照以下步骤操作,并追溯到您的步骤。

enter image description here

提示和先决条件,然后尝试此提议的解决方案。请确保您具有样式指南设置,例如Eslint,太好了。就我而言,我用cra复制了源代码,然后整理出遇到的第一个和最后一个问题。

  1. 尤其要小心使用useEffect之类的React钩子。避免在组件中造成副作用。 就我而言,我创建了一个可重用的useUpdateEffect hook,我打算解决这个问题的名称就是检测React道具或窗口道具的更新,但事与愿违,我不会共享代码。

    另外,请检查是否传递了正确的预期期望的依赖关系,对此Eslint值得赞扬。

  2. 避免在React列表中使用随机密钥。在组件列表中使用唯一键和常数键,因为依赖于它来标识每个项目。根据{{​​3}}

    键可帮助React识别哪些项目已更改,添加或删除。应该为数组内的元素提供键,以赋予元素稳定的身份。您可以将项目索引用作最后的选择:

  3. 避免在reducer和React组件中发生变量名冲突。请考虑使用样式指南作为您的朋友,以避免这种情况。

    我犯了一个愚蠢的错误,即创建Foo类并在其render函数中使用它,这也导致了死机。在这里写下所有可能再次遇到此问题的人。react library

  4. 避免无限循环,想象一下一次渲染很多数据。 follow this thread

    this happen,我敦促您检查循环,确保没有+ =而不是-=(反之亦然)。那些无限循环可能会给脖子带来很大的痛苦。

  5. 保持您的减速器为减速器,避免操作创建者,减速器中的API调用或using another reducer in your reducer,例如reducerA中的reducerB。当您调用reducerA中的更新reducerB时,reducerA中的更新将触发reducerB中的更新,从而导致页面/屏幕多次重新呈现。例如

// this react reducer in my case
// reducer js file - reducerB
const useBusinesses = () => {
  // reducerB as discussed above - the loading context 
  const { loading } = useLoadingContext(); // the culprit
  const [data, setData] = useState(initialState); // initial state, 
  const [state, dispatch] = useReducer(reducer, data);

  useEffect(() => setData(state), [state, setData]);

  const { businesses, errorMessage } = state;

  const setBusinesses = (payload) => dispatch({ type: `${FETCH_BUSINESSES}_SUCCESS`, data: payload });

  const setBusinessesError = (payload) =>  dispatch({ type: `${FETCH_BUSINESSES}_ERROR`, data: payload });

  const fetchBusinesses = async (lglt, type = 'food', limit = 12) => {
    try {
      // update reducerB: triggers multiple update in reducerA while requesting is pending
      loading(FETCH_BUSINESSES, true);
      const request = await API.businesses.getWithquery(
        `long=${lglt[0]}&latt=${lglt[1]}&limit=${limit}&type=${type}`
      );
      loading(FETCH_BUSINESSES, false);
      setBusinesses(request.data);
    } catch (err) {
      loading(FETCH_BUSINESSES, false);
      // if (!err.response) dispatch(alertMessage(FETCH_BUKKAS, true, 'Please check your network'));
      setBusinessesError(err.response.data);
    }
  });

  return { businesses, errorMessage, fetchBusinesses };
};

export const [BusinessesProvider, useBusinessesContext] = constate(useBusinesses);

//home js file
Home = () => {
  const { fetchBusinesses } = useBusinessContext();
  conso.log('home re-rending')
  // some hooks
  useEffect(() => {
    console.log('am i in trouble, yes!, how many troubles')
    fetchBusinesses(coordinates)
  }, [fetchBusinesses, coordinates])

  return <BigComponent />
}