Home > OS >  ReactJs : Call method from another component having no relation (parent-child)
ReactJs : Call method from another component having no relation (parent-child)

Time:12-24

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.

  • Related