gpt4 book ai didi

javascript - react 上下文不更新

转载 作者:行者123 更新时间:2023-12-01 16:18:08 26 4
gpt4 key购买 nike

我已经设置了一个使用 Context 来存储页面标题的基本示例项目,但是当我设置它时,组件不会重新呈现。

主要文件:

上下文.js

import React from 'react'

const Context = React.createContext({})

export default Context

AppWrapper.js

import React from 'react'
import App from './App'
import Context from './Context'

function AppWrapper () {
return (
<Context.Provider value={{page: {}}}>
<App />
</Context.Provider>
)
}

export default AppWrapper

应用程序.js

import React, { useContext } from 'react';
import Context from './Context';
import Home from './Home';

function App() {
const { page } = useContext(Context)
return (
<>
<h1>Title: {page.title}</h1>
<Home />
</>
);
}

export default App;

主页.js

import React, { useContext } from 'react'
import Context from './Context'

function Home () {
const { page } = useContext(Context)
page.title = 'Home'

return (
<p>Hello, World!</p>
)
}

export default Home

full code

我究竟做错了什么?

最佳答案

就像你想一个组件一样考虑 React 上下文,如果你想更新一个值并显示它,那么你需要使用 state .在这种情况下,您的 AppWrapper渲染上下文提供程序的位置是您需要跟踪状态的位置。

import React, {useContext, useState, useCallback, useEffect} from 'react'

const PageContext = React.createContext({})

function Home() {
const {setPageContext, page} = useContext(PageContext)
// essentially a componentDidMount
useEffect(() => {
if (page.title !== 'Home')
setPageContext({title: 'Home'})
}, [setPageContext])
return <p>Hello, World!</p>
}

function App() {
const {page} = useContext(PageContext)
return (
<>
<h1>Title: {page.title}</h1>
<Home />
</>
)
}

function AppWrapper() {
const [state, setState] = useState({page: {}})
const setPageContext = useCallback(
newState => {
setState({page: {...state.page, ...newState}})
},
[state, setState],
)
const getContextValue = useCallback(
() => ({setPageContext, ...state}),
[state, updateState],
)
return (
<PageContext.Provider value={getContextValue()}>
<App />
</PageContext.Provider>
)
}
编辑 - 从链接存储库更新的工作解决方案
我重命名了一些更具体的东西,我不建议通过上下文传递 setState ,因为这可能会与组件中的本地状态混淆和冲突。我也省略了答案不需要的代码块,只是我改变的部分
src/AppContext.js
export const updatePageContext = (values = {}) => ({ page: values })
export const updateProductsContext = (values = {}) => ({ products: values })

export const Pages = {
help: 'Help',
home: 'Home',
productsList: 'Products list',
shoppingCart: 'Cart',
}

const AppContext = React.createContext({})

export default AppContext

src/AppWrapper.js
const getDefaultState = () => {
// TODO rehydrate from persistent storage (localStorage.getItem(myLastSavedStateKey)) ?
return {
page: { title: 'Home' },
products: {},
}
}

function AppWrapper() {
const [state, setState] = useState(getDefaultState())

// here we only re-create setContext when its dependencies change ([state, setState])
const setContext = useCallback(
updates => {
setState({ ...state, ...updates })
},
[state, setState],
)

// here context value is just returning an object, but only re-creating the object when its dependencies change ([state, setContext])
const getContextValue = useCallback(
() => ({
...state,
setContext,
}),
[state, setContext],
)
return (
<Context.Provider value={getContextValue()}>
...

src/App.js
...
import AppContext, { updateProductsContext } from './AppContext'

function App() {
const [openDrawer, setOpenDrawer] = useState(false)
const classes = useStyles()
const {
page: { title },
setContext,
} = useContext(Context)

useEffect(() => {
fetch(...)
.then(...)
.then(items => {
setContext(updateProductsContext({ items }))
})
}, [])

src/components/DocumentMeta.js
这是一个新组件,您可以使用它以声明式样式更新页面名称,从而减少每个 View 中的代码复杂性/冗余
import React, { useContext, useEffect } from 'react'
import Context, { updatePageContext } from '../Context'

export default function DocumentMeta({ title }) {
const { page, setContext } = useContext(Context)

useEffect(() => {
if (page.title !== title) {
// TODO use this todo as a marker to also update the actual document title so the browser tab name changes to reflect the current view
setContext(updatePageContext({ title }))
}
}, [title, page, setContext])
return null
}
aka 用法类似于 <DocumentMeta title="Whatever Title I Want Here" />
src/pages/Home.js
现在每个 View 只需要导入 DocumentMeta 和 Pages“枚举”来更新标题,而不是每次都将上下文拉入并手动执行。
import { Pages } from '../Context'
import DocumentMeta from '../components/DocumentMeta'

function Home() {
return (
<>
<DocumentMeta title={Pages.home} />
<h1>WIP</h1>
</>
)
}
注意:其他页面需要复制主页正在做的事情
请记住,这不是我在生产环境中这样做的方式,我会编写一个更通用的助手来将数据写入缓存,它可以在性能、深度合并等方面做更多的事情。但这应该是一个很好的起点。

关于javascript - react 上下文不更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60697733/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com