【问题标题】:useEffect is running when any function is running当任何函数运行时 useEffect 正在运行
【发布时间】:2020-11-12 11:06:29
【问题描述】:

首先,我对这个问题进行了很多研究,但找不到解决方案。如果您能提供帮助,我将不胜感激。

功能组件

我在下面简要添加代码。这不是完整的代码

状态和道具

  // blog id
  const { id } = props.match.params;

  // state
  const initialState = {
    title: "",
    category: "",
    admin_id: "",
    status: false
  };

  const [form, setState] = useState(initialState);
  const [adminList, setAdminList] = useState([]);
  const [articleText, setArticleText] = useState([]);
  const [me, setMe] = useState([]);
  const [locked, setLocked] = useState(true);
  const timerRef = useRef(null);

// queries and mutations 

  const { loading, error, data } = useQuery(GET_BLOG, {
    variables: { id }
  });

  const { data: data_admin, loading: loading_admin } = useQuery(GET_ADMINS);

  const [editBlog, { loading: loadingUpdate }] = useMutation(
    UPDATE_BLOG
  );
  const [lockedBlog] = useMutation(LOCKED_BLOG);

多种使用效果和功能

useEffect(() => {
    if (!loading && data) {
      setState({
        title: data.blog.title,
        category: data.blog.category,
        admin_id: data.blog.admin.id,
        status: data.blog.status
      });
      setArticleText({
        text: data.blog.text
      });
    }
    console.log(data);
  }, [loading, data]);

  useEffect(() => {
    if (!loading_admin && data_admin) {
      const me = data_admin.admins.filter(
        x => x.id === props.session.activeAdmin.id
      );
      setAdminList(data_admin);
      setMe(me[0]);
    }
  }, [data_admin, loading_admin]);

  useEffect(() => {
    const { id } = props.match.params;
    lockedBlog({
      variables: {
        id,
        locked: locked
      }
    }).then(async ({ data }) => {
      console.log(data);
    });
    return () => {
      lockedBlog({
        variables: {
          id,
          locked: false
        }
      }).then(async ({ data }) => {
        console.log(data);
      });
    };
  }, [locked]);

  // if loading data
  if (loading || loading_admin)
    return (
      <div>
        <CircularProgress className="loadingbutton" />
      </div>
    );

  if (error) return <div>Error.</div>;

  // update onChange form
  const updateField = e => {
    setState({
      ...form,
      [e.target.name]: e.target.value
    });
  };

  // editor update
  const onChangeEditor = text => {
    const currentText = articleText.text;
    const newText = JSON.stringify(text);
    if (currentText !== newText) {
      // Content has changed
      if (timerRef.current) {
        clearTimeout(timerRef.current);
      }
      setArticleText({ text: newText });
      if (!formValidate()) {
        timerRef.current = setTimeout(() => {
          onSubmitAuto();
        }, 10000);
      }
    }
  };

  // auto save
  const onSubmitAuto = () => {
    if (timerRef.current) {
      clearTimeout(timerRef.current);
    }
    editBlog({
      variables: {
        id,
        admin_id,
        title,
        text: articleText.text,
        category,
        status
      }
    }).then(async ({ data }) => {
      console.log(data);
    });
  };

  // validate

  const formValidate = () => {
    const { title, category } = form;
    return !title || !articleText.text || !category;
  };

  // clear state
  const resetState = () => {
    setState({ ...initialState });
  };

  return (
    // jsx
  )

第一个问题,当调用onSubmitAuto 时,第一个useEffect 再次运行。我不想要这个。 因为我只希望它在第一次安装上工作。

第二个问题,如果articleText 状态之前发生了变化,那么在突变时它不会改变表单状态中的数据。但如果表单状态首先发生变化,它会改变所有数据。我觉得这个问题和第一个问题是一样的。

我希望我能解释这个问题。 :/

【问题讨论】:

  • 首先,当您调用 onSubmitAuto 时,它会再次运行最后一个 useEffect 因为 useEffect 具有 [locked] 并且您更改了 locked in onSubmitAuto 每次它改变 locked 的状态时都会运行你最后一次使用的 useEffect
  • 我没有锁定的问题,我从onSubmitAuto中删除了锁定。同样的问题还在继续。我更新了代码。问题在于 onSubmitAuto 和第一个 useEffect。 @费尔南多拉米雷斯

标签: javascript reactjs graphql apollo apollo-client


【解决方案1】:

Ciao,我对第一个问题有一个答案:当onSubmitAuto 被触发时,它调用editBlog 改变loadingloading 位于第一个 useEffect deps 列表中。 如果你不想这样,修复可能是这样的:

const isInitialMount = useRef(true);
//first useEffect
useEffect(() => {
if(isInitialMount.current) {
if (!loading && data) {
  setState({
    title: data.blog.title,
    category: data.blog.category,
    admin_id: data.blog.admin.id,
    status: data.blog.status
  });
  setArticleText({
    text: data.blog.text
  });
}
console.log(data);
if (data !== undefined) isInitialMount.current = false;
}
}, [loading, data]);

【讨论】:

  • 感谢您的回答,但现在 setState 在第一次加载时不起作用,所以 useEffect 现在不起作用。
  • 当我测试此代码时,'console.log(data)' 返回未定义。 @Giovanni Esposito
  • Ciao,如果在我的建议之前工作,也应该在我的建议之后工作。我所做的只是使用 bool ref 执行一次 useEffect 中的代码。很奇怪……反正如果 data 为 null if(!loading && data) 返回 false 并且 setState 将不会被执行。
  • 旧代码在控制台中也出现了 1 次未定义,然后数据来了。我们如何使 useQuery 数据异步?我不知道这是正确的,但是 useEffect 正在尝试在安装后立即获取数据。
  • 旧代码正确加载数据。但正如我所说,它给出了一次未定义。
猜你喜欢
  • 2020-10-22
  • 2013-08-18
  • 2021-10-06
  • 2022-12-16
  • 1970-01-01
  • 2021-09-27
  • 2020-06-25
  • 1970-01-01
  • 2021-12-13
相关资源
最近更新 更多