I have a component ->
AppLanding Component which renders 2 other components -
AppActions
AppListings
AppActions & AooListings do not have connection between them.
From the click of button in AppAction , I want to call method in AppListings.
Necessity of this -
AppListings contains Ag-Grid and AppActions contains button actions. On click of button in AppActions , I want to call method in AppListings which controls columnapi for Ag-Grid in AppListings
If it would have parent child relation , I would have passed method to AppListings , but in this case I cannot as it does not have relation.
CodePudding user response:
You want sibling components to communicate. You may want to look at this answer: https://stackoverflow.com/a/36144048/1065780
The idea is either to use state managers like redux, or to make your parent component receive events from one sibling and pass changed props to another sibling, like this:
function AppLanding() {
const [isSomethingToggled, setIsSomethingToggled] = React.useState(false);
const handleAction = () => {
setIsSomethingToggled(!isSomethingToggled);
};
return (
<div>
<AppActions onClick={handleAction} />
<AppListings isSomethingToggled={isSomethingToggled} />
</div>
);
}
function AppActions({ onClick }) {
return (
<div>
<button onClick={onClick}>Click action</button>
</div>
);
}
function AppListings({ isSomethingToggled }) {
return <div>Is something toggled: {isSomethingToggled ? 'yes' : 'no'}</div>;
}
ReactDOM.render(<AppLanding />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root">
</div>
CodePudding user response:
You can use redux on click event of button in AppActions page and listen the redux state with useeffect in AppListings page.
const AppActions = (props) =>{
const clickEvent = () => {
//you can add page restriction
props.setReduxState({callMethod:true/*, page:"AppActions"*/})
}
return <button onClick={clickEvent}>Button</button>
}
const mapDispatchToProps = {
setReduxState: reduxStateOperations.setReduxState
}
const connector = Redux.connect(null, mapDispatchToProps);
export default connector(AppActions);
const AppListings = (props) =>{
const method = () => { console.log("called") }
useEffect(() => {
if(props.reduxState?.callMethod) {
method()
props.setReduxState(undefined)
}
}, [props.reduxState])
return <>AppListings Page</>
}
const mapStateToProps = (state: any) => {
return {
reduxState: state.reduxState.reduxState,
}
}
const mapDispatchToProps = {
setReduxState: reduxStateOperations.setReduxState
}
const connector = Redux.connect(mapStateToProps, mapDispatchToProps);
export default connector(AppListings);
CodePudding user response:
Have you had a look into using React.Context to create a global provider (or specifically scoped around your layouts)? This way you could store your actions within a reducer.
hooks/use-context.jsx
import React from 'react'
// Set a relevant initial state
const INITIAL_STATE = {}
// Add actions for your application
const ACTIONS = {
UPDATE_VAR: 'update-var',
DELETE_VAR: 'delete-var'
}
const reducer = (state, action) => {
const next = { ...state } // Shallow copy
switch (action.type) {
case ACTIONS.UPDATE_VAR:
next.var = action.data
break
case ACTIONS.DELETE_VAR:
delete next.var
break
}
return next
}
const Context = React.createContext({
state: { ...INITIAL_STATE },
dispatch: () => null
})
export const Provider = ({ children }) => {
const [state, dispatch] = React.useReducer(
reducer, init(false)
)
return (
<Context.Provider value={[state, dispatch, ACTION]}>
{children}
</Context.Provider>
)
}
// Rename to something relevant
const useContext = () => {
const [state, dispatch] = React.useContext(Context)
return [state, dispatch]
}
export default useContext
pages/index.jsx: Provide state
import { Provider } from '../hooks/use-context'
const Page = () => (
<Provider>
<AppActions />
<AppListings />
</Provider>
)
export default Page
components/app-actions.jsx: Update state
import useContext from '../hooks/use-context'
const AppActions = () => {
const [, dispatch] = useContext()
return (
<button onClick={() => dispatch(/* action */)>
Click Me
</button>
)
}
export default AppActions
components/app-listings.jsx: Consume state
import useContext from '../hooks/use-context'
const AppListings = () => {
const [state] = useContext()
return (
<pre>{JSON.stringify(state, null, 2)</pre>
)
}
export default AppListings
You could also look into third-party solutions such as Redux.
