【问题标题】:React useEffect hook dependent on a second effectReact useEffect hook 依赖于第二个效果
【发布时间】:2020-02-21 08:28:07
【问题描述】:

当我的组件最初安装时,我正在使用 useEffect 挂钩异步获取数据。我还想使用效果(或更适合这种情况的其他钩子)来转换这些数据,当我的组件最初安装时也是如此。

引用上下文并初始化enhancedSections本地状态

  const displayContext = useContext(DisplayContext);
  const { sections } = displayContext;

  const schemaContext = useContext(SchemaContext);
  const { schema, getSchema } = schemaContext;

  const [enhancedSections, setEnhancedSections] = React.useState(sections);

在挂载时获取数据(可行)

  useEffect(() => {
    async function fetchData() {
      await getSchema()
    }
    fetchData();
  }, []);

转换获取的数据,setEnhancedSections
这里的问题是schema此时仍然为空

  useEffect(() => {
      let newSectionsArr = [];
      const schemaData = schema.data; //schema hasn't fetched yet
      Object.entries(sections).forEach(section => {
        let sectionKey = section[0];
        for(var i = 1; i < section.length; i++){
          section[i].forEach(item => {
            let table = schemaData.find(table => table[item.definition.table_name]);
            if (table) {
              let obj = table[item.definition.table_name].columns.find(column => column.field === item.definition.field_name);
              if (obj) {
                item.definition.description = obj.description;
                item.section = sectionKey;
                newSectionArr.push(item);
              }
            }
           setEnhancedSections(newSectionArr); // infinite loop...different problem
          });
        }
      });
  }, []);

当我将上述内容从 useEffect 中提取并放入基本 if 语句时,它可以工作(无限循环仍然是一个问题)...

 if(schema && sections){
      let newSectionArr = [];
       ...
    }

我知道我应该根据 React 文档使用多种效果来分离关注点,但我不确定如何让一种效果“等待”另一种效果。

感谢您的帮助。

【问题讨论】:

  • 如果我的回答不起作用,请告诉我。我对此很有信心,但如果没有,我还有其他想法。

标签: reactjs async-await infinite-loop react-hooks use-effect


【解决方案1】:

第二部分不需要在useEffect 中,它只是从您现有的状态派生而来。因为您正在调用setEnhancedState,所以您遇到了一个无限循环,但enhancedState 是派生的,并且不需要存在于状态本身中。您的最终组件可能如下所示:

const displayContext = useContext(DisplayContext);
const { sections } = displayContext;

const schemaContext = useContext(SchemaContext);
const { schema, getSchema } = schemaContext;

// No need for redundant enhancedSections state

useEffect(() => {
  async function fetchData() {
    await getSchema()
  }
  fetchData();
}, []);

let enhancedSections = [];
const schemaData = schema ? schema.data : [];
Object.entries(sections).forEach(section => {
  let sectionKey = section[0];
  for(var i = 1; i < section.length; i++){
    section[i].forEach(item => {
      let table = schemaData.find(table => table[item.definition.table_name]);
      if (table) {
        let obj = table[item.definition.table_name].columns.find(column => column.field === item.definition.field_name);
        if (obj) {
          item.definition.description = obj.description;
          item.section = sectionKey;
          enhancedSections.push(item);
        }
      }
    });
  }
});

// Use enhancedSections as you need now

【讨论】:

  • 这个解决方案仍然抛出“无法读取 'data' null 的属性”,因为 fetchData() 还没有检索到架构数据。如果我用 if(schema){...} 包装 for 循环,它可以工作......但我认为浮动 if 语句不是最佳做法。
  • @BWeb303 更新为在分配给schemaData 时首先快速检查架构是否存在...在这种情况下,三元运算符应该更可口。
  • 三元运算符起作用了。但是,我确实需要将enhancedSections 设置为本地状态变量,因为它将在整个组件中被访问/更新。我将setEnhancedSections 在此 for 循环的内部/外部的哪个位置避免无限循环?谢谢
  • 出于好奇,enhancedSections 是如何被修改的?我只是问,因为例如,如果修改是应用过滤器或类似的东西,您实际上可以将过滤器设置为状态
猜你喜欢
  • 2021-02-23
  • 2019-08-09
  • 2021-05-11
  • 2020-10-26
  • 2021-12-04
  • 2020-08-09
  • 2019-10-24
  • 2020-03-07
  • 2020-02-25
相关资源
最近更新 更多