使用useEffect()管理功能组件的状态

时间:2020-04-07 10:31:24

标签: javascript reactjs

假设我有一个App.jsx:

App.jsx

const App = () => {
    return (
        <React.Fragment>
            <NavBar />
            <BooksList />
            <TextEditor />
        </React.Fragment>
    )
}

export default App;


BooksListTextEditor是2个功能组件。在一个组件中,我能够将编辑器的内容保存到数据库中:

Editor.jsx

const TextEditor = () => {
    return(
        <*editor related stuff*>
    )
}

const SaveContent = ({ value, icon }) => {
    return (
        <SaveButton
            onMouseDown={async () => {
                console.log(JSON.stringify(value));
                const response = await fetch('/add_book', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },

                    body: JSON.stringify(value)

                })

                if (response.ok) {
                    console.log('response okay')
                }
            }}
        >
            <Icon icon={icon}></Icon>
        </SaveButton>
    )
}

成功写入我的数据库。

我想让BookList组件在保存/删除项目时自动用数据库的内容更新。这是我到目前为止拥有的BookList组件:

BooksList.jsx

const BooksList = () => {
    const [books, setBooks] = useState([]);

    useEffect(() => {
        fetch('/get_books')
        .then(response => 
            response.json()
        .then(data => {
            setBooks(data)
        })
        );
    }, [])

    return (
        <*list of saved editors*>
    )
}

因此,在加载时,如果数据库为空,则不显示任何内容。当我保存到数据库时,它什么也没有显示,然后在刷新页面时,它显示了我想要取回的数据。我希望能够保存数据并查看上述组件的刷新和自动更新。

我是React和JS的新手,所以任何指针都很棒。我认为可能需要重写以使用基于类的组件来简化状态管理?但是我不确定。我的基本理解是useEffect()在功能上等同于基于类的安装方法。这使我相信可以做到这一点。但是,我读过有状态组件应使用基于类的组件。

谢谢, 亚历克斯

3 个答案:

答案 0 :(得分:0)

有几种不同的方法可以做到这一点,这都取决于组件的结构。最重要的是,当您成功发布到数据库时,您需要触发GET请求。一种快速,肮脏的解决方案是将GET请求移到一个单独的函数中,并在useEffect中调用它,并将该函数作为道具传递给下一个。像这样:

Editor.jsx

const SaveContent = ({ value, icon, refreshBooksList }) => {
    const addBook = useCallback(async () => {
        const response = await fetch('/add_book', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },

            body: JSON.stringify(value)

        })

        if (response.ok) {
            console.log('response okay')
            refreshBooksList()
        }
    }, [value, refreshBooksList])

    return (
        <SaveButton
            onMouseDown={addBook}
        >
            <Icon icon={icon}></Icon>
        </SaveButton>
    )
}

BooksList.jsx

const BooksList = () => {
    const [books, setBooks] = useState([]);

    const getBooksList = useCallback(async () => {
        await fetch('/get_books')
            .then(response => 
                response.json()
            .then(data => {
                setBooks(data)
            })
        );
    }, [setBooks])

    useEffect(() => {
        getBooksList()
    }, [])

    return (
        <*list of saved editors*>
    )
}

如果两个组件都不是父级/子级,则需要将getBooks函数在树上移动到共享的父级。

根据API返回的内容,您可以完全删除其他GET请求,而只需更新状态即可。如果是这种情况,可以考虑使用React Context来避免传递道具。

答案 1 :(得分:0)

如果您的Editor和BookList组件位于同一父组件内,则可以在Parent组件内使用状态。父级会将回调传递给编辑器。编辑器将使用此回调来通知父级有一本新书。父级将增加状态并将该状态作为道具传递给BookList。然后BookList将检查useEffect中的道具是否已更改,并重新加载书籍列表。

这是一个最小的代码示例:

const Parent = () => {
  const [x, setX] = React.useState(0);
  const onNewBook = () => {
    setX(state => state+1);
  }
  return (
    <>
      <BookList x={X} />
      <Editor onNewBook={onNewBook} />
    </>
  )
}

const Editor = (props) => {
  onSave = () => {
    // Save the editor to the DB
    props.onNewBook();
  }
}

const BookList= (props) => {
  React.useEffect(() => {
    // Reload the list from DB
  }, [props.X])
}

答案 2 :(得分:0)

如果Editor和BookList不在同一个Parent组件内,则可以使用事件在Editor和BookList之间进行通信。编辑器可以发送事件,而BookList可以监听这些事件。

BookList

document.body.addEventListener('updateBookList', onUpdateBookList, false);

编辑器

const myEvent = new CustomEvent('updateBookList');
document.body.dispatchEvent(myEvent);