[英]How to access a prop in a layout component if my component is being passed to the layout component as a chilren prop in ReactJS?
我有一個Layout
組件,其中包含一個名為isLightMode
的狀態,我想將其作為道具傳遞給其他組件以供訪問和使用。
這是我的Layout
組件:
import React from 'react'
import Main from '../components/main'
export default class Layout extends React.Component {
constructor(props) {
super(props)
this.state = { isLightMode: true }
this.toggleTheme = this.toggleTheme.bind(this)
}
toggleTheme() {
this.setState(state => ({
isLightMode: !state.isLightMode,
}))
}
render() {
const { isLightMode } = this.state
const { children } = this.props
return (
<div>
<Navigation
isLightMode={isLightMode}
onToggleTheme={this.toggleTheme}
/>
{children && <Main isLightMode={isLightMode}>{children}</Main>}
</div>
)
}
}
特別是,我有一個Home
組件,我想訪問isLightMode
:
import React from 'react'
import Layout from '../layouts/layout'
import AvatarLight from '../../content/assets/img/avatar-light.png'
import AvatarDark from '../../content/assets/img/avatar-dark.svg'
const Home = props => {
return (
<Layout>
<img src={props.isLightMode ? AvatarLight : AvatarDark} />
</Layout>
)
}
export default Home
這是我的Main
組件,我可以在其中訪問props.isLightMode
,但我想從Home
組件訪問它:
import React from 'react'
const Main = (props) => {
return (
<main className="main">
<div>lightmode:{props.isLightMode}</div>
<div className="container">{props.children}</div>
</main>
)
}
export default Main
那么如何從我的Home
組件訪問Layout
組件中的isLightMode
呢?
使用createContext
來包裝訪問狀態所需的所有組件。 並通過Consumer
使用它(使用鈎子更清潔)。
const Theme = React.createContext({ isLightMode: true });
// Consume the context in Home and in Layout
const App = () => (
<Theme.Provider>
<Home />
</Theme.Provider>
);
這是一個帶有鈎子的例子,可以用類來實現。
const Home = props => {
const isLightRef = createRef(false);
// In layout call props.isLightPref.current = true / false.
return (
<Layout isLighRef={isLightRef}>
<img src={isLightRef.current ? AvatarLight : AvatarDark} />
</Layout>
);
};
Home
--- Layout
--- Navigation
--- Main
您的代碼的結構方式isLightMode
需要在Home
因此它也將在Layout
范圍內:
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = { isLightMode: true };
this.toggleTheme = this.toggleTheme.bind(this);
}
toggleTheme() {
this.setState(state => ({
isLightMode: !state.isLightMode
}));
}
render() {
return (
<Layout isLightMode={this.toggleTheme} toggleTheme={this.toggleTheme}>
<img src={this.isLightMode ? AvatarLight : AvatarDark} />
</Layout>
);
}
}
const Layout = ({ children, isLightMode }) => {
return (
<div>
<Navigation isLightMode={isLightMode} onToggleTheme={this.toggleTheme} />
{children && <Main isLightMode={isLightMode}>{children}</Main>}
</div>
);
};
更好的方法是從那里創建上下文和消費者。 但是你可以使用React.cloneElement來傳遞數據:
所以在你的情況下,你可以做這樣的事情:
class Layout extends React.Component {
constructor(props) {
super(props);
this.state = { isLightMode: true };
this.toggleTheme = this.toggleTheme.bind(this);
}
toggleTheme() {
this.setState(state => ({
isLightMode: !state.isLightMode
}));
}
render() {
const { isLightMode } = this.state;
const { children } = this.props;
return (
<div>{children && <Main isLightMode={isLightMode}>{children}</Main>}</div>
);
}
}
在您的家庭組件中,您可以直接使用:
const Main = props => {
return (
<main className="main">
<div>lightmode:{String(props.isLightMode)}</div>
<div className="container">
{React.cloneElement(props.children, props)} // pass props data to children
</div>
</main>
);
};
const Home = props => {
return <>{props.isLightMode ? "AvatarLight" : "AvatarDark"}</>;
};
這是工作鏈接: https : //codesandbox.io/s/busy-resonance-x69gm
您可以通過將回調函數作為道具從 Home 組件傳遞給 Layout 組件來完成它,因此一旦 isLightMode 的狀態發生更改,您就可以調用該函數並更改 Home 中的 isLightMode 值。
const Home = props => {
return (
<Layout
onChangeMode={(mode) => setLightMode(mode)}
>
<img src={props.isLightMode ? AvatarLight : AvatarDark} />
</Layout>
)
}
所以 toggleTheme 將變成,
toggleTheme() {
this.setState(state => ({
isLightMode: !state.isLightMode,
}), () => {
this.props.onChangeMode(this.state.isLightMode);
})
}
在 Home 組件中,您將不得不使用 useState hook 或 state 來維護 isLightMode 的值並將其傳遞給 img 標簽。
希望這是您所需要的,它可以解決您的問題。
腳步:
Context
對象和Context.Provider
組件Context.Provider
組件中contextType
屬性(或Context.Consumer
)來使用context
1. 創建Context
對象和Context.Provider
組件:
import react from 'React'
const defaultValue = {
isLightMode: true,
toggleTheme: () => {},
}
// create Context object called ThemeContext
const ThemeContext = React.createContext(defaultState)
// create Context.Provider component called ThemeProvider
class ThemeProvider extends React.Component {
state = {
isLightMode: true,
}
toggleTheme = e => {
e.preventDefault()
const isLightMode = !this.state.isLightMode
localStorage.setItem('isLightMode', JSON.stringify(isLightMode))
this.setState({ isLightMode })
}
componentDidMount() {
const isLightMode = JSON.parse(localStorage.getItem('isLightMode'))
if (isLightMode) {
this.setState({ isLightMode })
}
}
render() {
const { children } = this.props
const { isLightMode } = this.state
return (
<ThemeContext.Provider
value={{
isLightMode,
toggleTheme: this.toggleTheme,
}}
>
{children}
</ThemeContext.Provider>
)
}
}
2. 將您的根元素包裝在Context.Provider
組件中:
import React from 'react'
import { ThemeProvider } from './src/context/ThemeContext'
export const wrapRootElement = ({ element }) => (
<ThemeProvider>{element}</ThemeProvider>
)
3. 使用contextType
屬性來消費context
:
主頁組件
import React from 'react'
import Layout from '../layouts/layout'
import ThemeContext from '../context/ThemeContext'
import AvatarLight from '../../content/assets/img/avatar-light.png'
import AvatarDark from '../../content/assets/img/avatar-dark.svg'
export default class Home extends React.Component {
static contextType = ThemeContext
render() {
const { isLightMode } = this.context
return (
<Layout>
<img src={isLightMode ? AvatarLight : AvatarDark} />
</Layout>
)
}
}
導航組件
import React from 'react'
import Layout from '../layouts/layout'
import ThemeContext from '../context/ThemeContext'
import AvatarLight from '../../content/assets/img/avatar-light.png'
import AvatarDark from '../../content/assets/img/avatar-dark.svg'
export default class Home extends React.Component {
static contextType = ThemeContext
render() {
const { isLightMode, toggleTheme } = this.context
return (
<nav>
<a onClick={toggleTheme}>{isLightMode ? 'Light mode' : 'Dark mode'}</a>
</nav>
)
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.