score:2

Accepted answer

It's a question of how you want to store state in your app really.

Take a simple example where a component which is a child of another. In that case, the parent can store the state locally e.g. useState() and pass it down as props to the child.

const SomeParent = () => {
  const [isTrue, setIsTrue] = React.useState(true)
  return (
    <Child isTrue={isTrue} />
  )
}

There may be cases where you want to share state across multiple components, or across your whole app. In that case, you have a load of different options.

1. Lifting state up to the highest point you need.

It would be easiest to move your state which is shared between multiple components up to the highest point that the two components share. e.g.

Section component <- store state here
  Parent one
    child one
    child two
  Parent two
    child one

Here you can again either useState() or alternatively store the state in a useReducer() and pass dispatch down.

The data flow would then look something like this:

  1. initialise state in the section component e.g. const [someState, setSomeState]
  2. pass the setSomeState callback down to the Parent component and in turn child component as a prop e.g.
  3. In the child component set state onClick using the callback e.g. onClick = {() => action(item)}
  4. pass the state value down to your second Parent component and in turn child component e.g.
  5. You have access to the state in your form

This can be an object or multiple state values. As complexity increases, I tend to reach for useReducer().

2. Implementing useContext OR Redux in your application to create an application state accessible from any component (This is a much bigger explanation and there are lots of resources on each...

NOTE: I'm not sure why you're using two sets of brackets here:

const handleClick = (value) => () => {
   console.log(value);
 };

and when you're calling handleClick you need to switch it for an arrow function if you're passing a value:

onClick={handleClick({ item })

...

onClick={() => handleClick(item)}

score:0

basically, you want to trigger a class component function from a functional component by passing item prop, if it was a parent child components you can pass a function as a prop and trigger it whenever you want from your parent or child component.

but in your case both components are not connected, what you can do without using redux is to create a public local storage for ex let's call it localStorage.js :

var PublicData = (function() {

  var data = null;

  var getData = function() {
    return data;
  };

  var setData = function(props) {
    data = props;  
  };

  var clearData = function() {
    data = null;
  };

  return {
    GET: getData,
    SET: setData,
    CLEAR: clearData
  }

})();

export default PublicData;

then you import it and use like the following :

import PublicData from './PublicData.js';

PublicData.SET(apiData); // you set your data once you fetch it 
const data = PublicData.GET(); // get data 
PublicData.CLEAR(); // clear your data

Note : this is not an actual localStorage, but it work the same, it will help you to share variables between your components.

score:0

Try this:

const handleClick = (value) => {
 console.log(value);
};

<Button variant="outlined" onClick={() => handleClick({ item })} />

score:0

    Parent
   /      \
Service  Event

I'm guessing from your question that a simplification of your app tree looks like the above.

The problem you are having is the following:

    Parent
   /      \
Service  Event
          Data

In a top down architecture Service does not know about Event and any data over there in the that branch.

So you have 2 options (likely more, but these 2 get you a long way):

  1. Hoist the data
    Parent
     Data
   /      \
Service  Event
  1. Store the data somewhere else and provide a mechanism for access
Data

    Parent
   /      \
Service  Event

Option 1 can be achieved by passing props (the data) and functions (passed using props) to manipulate the data (or, indeed, populate it in the first place i.e. fetch it)

The flow would look something like: Parent is stateful. Parent passes the current state of the data to children that care about it (in your case that looks like Service and Event). Parent passes a function to Event, which can be attached to a click handler within the Event subtree of elements.

Due to passing a function down, when that click handler is invoked it can set the state of the Parent, from which the normal top-down rendering flow will handle setting updates and passing the data changes down the tree, whereby they will (usually) invoke a re-render.

I think Recoil uses this method, and it is becoming increasing popular once more as we look to split applications up and eschew global state management.

Option 2 is where data management libraries like Redux, Cerebral, MobX et al live. If you’re familiar with the publisher/subscriber pattern then you'll know how they work.

In essence, these libraries hold shared state for your application, such as the data you have here. They then (typically) provide a pattern for you to manage changes to the state (via a published event) and ensure that components that subscribe to that data receive the new state and update.

The 'discussion' here differs from option 1: The click handler publishes an event, which, in essence, asks for some manipulation to the data. Manipulation occurs (or not), and subscribers are updated. In your case, the click would tell the centralised store/s (i.e. anything listening) to fetch the data, when it is done and the data is changed (from empty to filled) it lets all concerned elements (or, quite possibly, the entire application tree and leverage top-down rendering) know about it and they can do what they need to do.

Which option you pick is entirely up to you, they both have pros and cons.

Good luck thinking about your data, how you store it, and how you use it!

score:0

I'm glad you asked this question because this is a problem that has been faced and solved a lot of the times. Other contributors have written nice comprehensive answers so I'll keep it short.

1. Move shared stated to a common ancestor.

This one's pretty straight forward but gets very hairy very quickly.

2. Use Context API

You can use react's context API to move code responsible for fetching data to your context and use that data anywhere in your app without a lot of hassle. This approach is getting quite popular nowadays. Take a look at this and here's a sweet library to help you get started.

3. Use a state management library (preferred)

You can choose to use any state management library you like to solve this problem. There are quite a few options, and redux is the most popular one and for a very good reason. It enables you in implementing separation for concern between your data and your UI, but is a bit verbose.

Mobx is also popular and has a good developer experience but I personally don't like that it enforces a certain style to your code.

If you're new to react and state management then these libraries could be really daunting. I'd suggest you start with zustand. It's super simple and gets the job done. ;)

score:0

You can simply use Custom Event https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent. It is not the best practice but it work.In EventCard, when user click you dispatch a Custom event with payload is item, then ServiceForm will listener that event and store item as state. Working demo here https://codesandbox.io/s/distracted-aryabhata-ec6gc

EventCard

const handleClick = () => {
  const item = {
      description: "This is description"
  };
  const event = new CustomEvent("customEvent", {
      detail: item
  });
  window.dispatchEvent(event);
};

Service Form

const [item, setItem] = useState(null);
...
useEffect(() => {
  const handler = (e) => {
    setItem(e.detail);
  };
  window.addEventListener("customEvent", handler);

  return () => window.removeEventListener("customEvent", handler);
}, []);

Related Query

More Query from same tag