【问题标题】:Why does React state return undefined but page still loads from state OK?为什么 React 状态返回未定义但页面仍然从状态 OK 加载?
【发布时间】:2021-12-07 20:50:12
【问题描述】:

我正在尝试开发一个 React 应用程序,该应用程序调用数据库以将一组页面加载到板以构建拖放决策树。 我才刚刚开始使用 React,所以很想知道我在这里做错了什么。

使用“useEffect”,pageTree 函数将在第一次加载和每次刷新时加载页面,但是页面状态返回一个空数组而不是当前页面。 奇怪的是,页面都显示在板上,pages.map 函数适用于页面状态......(在 console.log 上返回为空......)

如果我向数组中添加一个页面,它会将更改保存到数据库中,但随后只会在板上显示新页面。然后您必须刷新才能看到新的页面集(包括添加的页面)。

添加或删除页面的调用由父组件中的布局菜单按钮调用。

Console after refresh

另外,如果我移动一个页面,状态会控制台OK:

Page state in console after moving a page. DB call and state update works OK

function PageTree({AddNewPageFunc}) {
  const [pages, setPages] = useState([]);
  const movePage = useCallback((droppedPage) => {
  const updatedPages = pages.map(page => droppedPage._id == page._id ? droppedPage : page);
  setPages(updatedPages);
    }, [pages]);

  const [{isOver}, drop] = useDrop(() => ({
        accept: ItemTypes.PAGECARD,
        drop(page, monitor) {
            const delta = monitor.getDifferenceFromInitialOffset();
            let x = Math.round(page.x + delta.x);
            let y = Math.round(page.y + delta.y);
            page.x = x;
            page.y = y;
            movePage(page);
            setNewPagePosition(page);
            return undefined;
        },
    }), [movePage]);

    const setNewPagePosition = async (pageDetails) => {
        console.log("function called to update page position");
        Api.withToken().post('/pageupdate/'+pageDetails._id,
            pageDetails
        ).then(function (response) {
            console.log("moved page: ",response.data)
        }).catch(function (error) {
          //console.log(error);
        });
    }

    React.useEffect(() => {
      AddNewPageFunc.current = AddNewPage
    }, [])

    const AddNewPage = useCallback(() => {
      console.log("calling add new page function")
      console.log("the pages before the API call are ",pages)
      Api.withToken().post('/addblankpage/'
        ).then(function (response) {
          console.log("produced: ",response.data);
          setPages(pages.concat(response.data))
          console.log("the pages after updating state are: ",pages)
      }).catch(function (error) {
        //console.log(error);
      });
    }, [pages]);

    const handleDelete = async (id) => {
        Api.withToken().post('/deletepages/'+id
        ).then(function (response) {
            let index = pages.findIndex(function(item){
              return item.id === response.data._id;
            });
            const PageRemoved = pages.splice(index, 1);
            setPages(PageRemoved);
        }).catch(function (error) {
          //console.log(error);
        });
    }

    useEffect(() => {
      Api.withToken().get('/pages/')
      .then(res => {
        setPages(res.data);
        console.log('res data ',res.data);
        console.log('pages ',pages);
      })
    }, []);

  return (
      <div ref={drop} style={styles}>
          {pages.map((page) => (<PageCard page={page} id={page._id} key={page._id} handleDelete={() => handleDelete(page._id)} handleMaximise={() => handleMaximise(page)} handleCopy={() => handleCopy(page)}/>))}
      </div>
      )
}

export default PageTree;

【问题讨论】:

  • 如果您在设置状态后立即尝试控制台,它不会显示更新后的值。在useEffect的依赖数组中添加pages,每当页面更新时,组件就会渲染。
  • 我试图将页面添加到依赖数组,但它会导致无限循环,因为 useEffect 在每次更改页面时都会发生(在加载时发生)。我尝试添加第二个 useEffect 来监控 pages.length 的变化,但可能做得不正确......
  • 抱歉,Daniel,我查看了错误的 useEffect,如果我为 AddNewPage useEffect 添加了页面回调,那么它可以解决添加新页面的问题。这绝对是一个回调问题。谢谢!

标签: reactjs react-native react-redux state


【解决方案1】:

正如 Danielprabhakaran 所指出的,问题在于 React.useEffect 中的回调。在添加新页面时,它需要将更新的页面状态发送回父组件。 在 API 调用之后在状态上使用 console.log 似乎很麻烦,即使使用 .then(console.log(state)

function PageTree({AddNewPageFunc}) {
  const [pages, setPages] = useState([]);
  const movePage = useCallback((droppedPage) => {
  const updatedPages = pages.map(page => droppedPage._id == page._id ? droppedPage : page);
  console.log("updated pages ",updatedPages);
  setPages(updatedPages);
  console.log("set pages ",pages);
    }, [pages]);

  const [{isOver}, drop] = useDrop(() => ({
        accept: ItemTypes.PAGECARD,
        drop(page, monitor) {
            const delta = monitor.getDifferenceFromInitialOffset();
            let x = Math.round(page.x + delta.x);
            let y = Math.round(page.y + delta.y);
            page.x = x;
            page.y = y;
            movePage(page);
            setNewPagePosition(page);
            return undefined;
        },
    }), [movePage]);

    const setNewPagePosition = async (pageDetails) => {
        console.log("function called to update page position");
        Api.withToken().post('/pageupdate/'+pageDetails._id,
            pageDetails
        ).then(function (response) {
            console.log("?worked ",response)
        }).catch(function (error) {
          //console.log(error);
        });
    }

    React.useEffect(() => {
      AddNewPageFunc.current = AddNewPage
    }, [pages])

    const AddNewPage = useCallback(() => {
      console.log("calling add new page function")
      console.log("the pages before the API call are ",pages)
      Api.withToken().post('/addblankpage/'
        ).then(function (response) {
          console.log("produced: ",response.data);
          setPages(pages.concat(response.data))
          console.log("the pages after updating state are: ",pages)
      }).catch(function (error) {
        //console.log(error);
      });
    }, [pages]);

    const handleDeletedCallback = (deletedIndex) => {
      console.log("delete callback fired")
      setPages(pages.splice(deletedIndex, 1));
    }

    useEffect(() => {
      Api.withToken().get('/pages/') //can add in a prop to return only a given tree once the app gets bigger
      .then(res => {
        setPages(res.data);
        console.log('res data ',res.data);
        console.log('pages ',pages);
      })
    }, []);

  return (
      <div ref={drop} style={styles}>
          {pages.map((page, index) => (<PageCard page={page} id={page._id} key={page._id} index={index} deleteCallback={handleDeletedCallback} handleMaximise={() => handleMaximise(page)} handleCopy={() => handleCopy(page)}/>))}
      </div>
      )
}

export default PageTree;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-08
    • 1970-01-01
    • 2018-09-25
    • 1970-01-01
    • 2023-04-03
    • 2018-12-31
    • 2018-08-22
    • 1970-01-01
    相关资源
    最近更新 更多