I have a bit of a basic React question that I am having trouble googling.
I have this component which is managing the state of maximize:
import React from 'react'
import { useState } from 'react';
import './Panel.scss'
import { AiFillExperiment, AiOutlineExpandAlt } from "react-icons/ai";
const Panel = ({title}) => {
const [maximize, setMaximize] = useState(false);
return (
<div className='panel'>
<AiFillExperiment />
<p>{title}</p>
<AiOutlineExpandAlt onClick={() => setMaximize(!maximize)} />
</div>
)
}
export default Panel
and this component that needs to be able to see the value of that state:
import './App.scss';
import { useEffect, useState } from 'react';
import ReactMarkdown from 'https://esm.sh/react-markdown@7'
import remarkBreaks from 'https://esm.sh/remark-breaks@3'
import Panel from './components/Panel'
function App() {
const [markdown, setMarkdown] = useState(``)
const placeholder =
`# Welcome to my React Markdown Previewer!
## This is a sub-heading...
### And here's some other cool stuff:
Here's some code, \`<div></div>\`, between 2 backticks.
\`\`\`
// this is multi-line code:
function anotherExample(firstLine, lastLine) {
if (firstLine == '\`\`\`' && lastLine == '\`\`\`') {
return multiLineCode;
}
}
\`\`\`
You can also make text **bold**... whoa!
Or _italic_.
Or... wait for it... **_both!_**
And feel free to go crazy ~~crossing stuff out~~.
There's also [links](https://www.freecodecamp.org), and
> Block Quotes!
And if you want to get really crazy, even tables:
Wild Header | Crazy Header | Another Header?
------------ | ------------- | -------------
Your content can | be here, and it | can be here....
And here. | Okay. | I think we get it.
- And of course there are lists.
- Some are bulleted.
- With different indentation levels.
- That look like this.
1. And there are numbered lists too.
1. Use just 1s if you want!
1. And last but not least, let's not forget embedded images:
![freeCodeCamp Logo](https://cdn.freecodecamp.org/testable-projects-fcc/images/fcc_secondary.svg)
`;
useEffect(() => {
setMarkdown(placeholder)
}, [placeholder])
return (
<div className="App">
{/* Editor Container */}
<div
className={'editor-container'}
>
<Panel title='Editor' />
<textarea id='editor' onChange={(e) => setMarkdown(e.target.value)} rows="" cols="">{placeholder}</textarea>
</div>
{/* Preview Container */}
<div className='preview-container'>
<Panel title='Preview' />
<div id='preview'>
<ReactMarkdown children={markdown} remarkPlugins={[remarkBreaks]} />
</div>
</div>
</div>
);
}
export default App;
How do I go about doing this? I realize I could have it all in one component, but I would like to know how to do it with two separate components.
Thanks in advance!
CodePudding user response:
Use redux or react context please, props drilling is bad practice
https://reactjs.org/docs/context.html
https://redux.js.org/
CodePudding user response:
Through useState props (less recommended)
You can do that by having that state in your App component and passing the setState as a property
const App = () => {
const [maximize, setMaximize] = useState(false);
const handleToggle = (newState) => {
setState(newState)
}
return (
<div>
<Panel toggleState={toggleState} maximize={maximize} />
</div>
)
}
And in your Panel component:
const Panel = ({toggleState, maximize}) => {
const handleToggle = () => {
toggleState(!maximize)
}
return (
<AiOutlineExpandAlt onClick={handleToggle} />
)
}
Through useContext hook
useContext allows you to store variables and access them on all child components within that context provider.
MaximizeProvider.js
import React, {useState, useContext} from "react";
//creating your contexts
const MaximizeContext = React.createContext();
const MaximizeUpdateContext = React.createContext();
// create a custom hook
export const useUpdate = () => {
return useContext(MaximizeUpdateContext)
}
export const use maximize = () => {
return usecContext(MaximizeContext)
}
//creating your component that will wrap the child components
const MaximizeProvider = ({children}) => {
const [maximize, setMaximize] = useState(false)
// Your toggle to switch the state
const toggle = () => {
setMaximize(prevState => !prevState)
}
return (
<MaximizeContext.Provider value={maximize}>
<MaximizeUpdateContext.Provider value={toggle}>
{children}
</MaximizeUpdateContext.Provider>
</MaximizeContext.Provider>
)
}
export {MAximizeProvider}
Both providers allow you to access both the state and the setState
App.js
import React, {useState} from "react";
// your context component
import {MaximizeProvider} from "./MaximizeProvider";
// a button component
import {ButtonComponent} from "./ButtonComponent";
const App = () => {
return (
<>
<MaximizeProvider>
<ButtonComponent/>
</MaximizeProvider>
< />
);
}
export {App};
in the App, you are wrapping the elements that need your context. as long as the elements and even children of children are in the wrap, it would have access to it the same way as in the button component.
ButtonComponent.js
import {useMaximize, useUpdate} from "./MaximizeProvider";
const ButtonComponent = () => {
const toggle = useUpdate();
const state = useMaximize()
return (
<button onClick={toggle}>Click</button>
);
}
export {ButtonComponent};
I hope this helps, I am not an expert, so there might be better ways to do it, but this seems to work for me.