Can two components have the exact same state, asynchronously updating? - javascript

Context:
I am working on a React App, and have two sibling components (NOTE: there is no parent-child component relationship) which both have one identical state. They need to asynchronously update (i.e. When Component1 causes the state to change, then Component2 should have knowledge of that state change and use the changed state as the initial state).
The Problem:
I am using useState(intitialValue) to set the states in each Component, but I am noticing that this is causing my states to go out of sync, as the state depends on modifications done by Component1 or Component2.
(i.e.)
If Component1 caused the state to change from "red" to "green" via some component method, and in Component2 I do:
useState("red")
Then Component2 did not correctly get the information of "green" that was from Component1; instead it received the information of "red" from the initialization of the initial state.
PS:
Please don't simply tell me to pass the state as props. Reminder these are NOT parent-child components!
Any help is greatly appreciated. I think this is a great and common ReactJS issue to solve.

If there is no any relation between two separated components, why they should be synchronous? the substantial question is that, what event do you expect cause to change state in both component? then you can subscribe both components to that event. event can be router change, received data from server asynchronously, browser based events (like resize) or common data changing in memory. some of these events have own hook like route change. But if your event is data change you can use a common service in the both like redux, rxjs or some other state management frameworks. Or if you are pro can write your own hook for your particular event.
If you had shared some sample code, it would help more.

Related

Understanding the props concept in React

While I'm learning React, it's always said that you should keep your state in the parent component and pass them as props to its children.
But in the real world, whenever I start building a react app, I end up passing data from a child component to its parent.
For example, if I have to implement a form somewhere in my react app, I create an extra component for it (for example, FormComponent) and import it in my App component.
But now, I have to pass the form data form the FormComponent to the App component. In other words, from the child component (FormComponent) to the parent (App component).
And this was just an example. Usually, I always end up in situations where I have to pass data from child to parent rather than the other way around.
Do I misunderstand the concept of passing props completely?
If we stay with the above example, is my approach, right?
You can't pass data from child to parent as in React, The Data Flows Down.
So usually you pass callbacks from parent to its children, but the state remains in the parent.
This is commonly called a “top-down” or “unidirectional” data flow. Any state is always owned by some specific component, and any data or UI derived from that state can only affect components “below” them in the tree.
If you in a situation where the code becomes unreadable, unmaintainable, you should consider Lifting the State Up.
Often, several components need to reflect the same changing data. We recommend lifting the shared state up to their closest common ancestor.
Aside from it, a common anti-pattern is Prop Drilling, Context API, and many state libraries like Redux, MobX, and Recoil trying to solve such problems with some extra features.
1- In your case you can pass a function ( Example: handleSubmit() ) through props from parent to child.
And so when this function is called the child's data would be hundled from the parent.
you can use this doc page to inspire your code.
2- Otherwise you can use react redux, and then you can hundle all data at any component in your project using one global state called redux store.
want to learn more about react redux click here.
3- Have a nice day ^_^ .

why is mapStateToProps/mapDispatchToProps defined in every file?

is there a reason people always seem to define these functions at the bottom of every component they are needed?
when ever I create a react/redux project I put these in a /mappingFunctions directory and then import them into the files I need them, thus declaring the functions just once. obviously means the functions include more than necessary but it means they are in just one place rather than defining them a million times.
just wondering why this is not the standard?
Each component/container may need to access different set of variables from redux store and different set of actions. So mapStateToProps and mapDispatchToProps are defined individually for all those components that need to interact with Redux store.
Also you don't need to use mapStateToProps, maDispatchToProps for each component. You can have a balance between passing props down or connecting each component to Redux store.
Check Use Connect or pass data as props to children for more details
Because the state and the actions passed to components are generally different
mapStateToProps - this is callback called by Redux when some part of the state is updated. It is used to update map Redux store changes to properties of your component. Each of your components is most probably interested in different parts of Redux store state. Your container components doesn't need to implement this if they don't need to be updated based on Redux store state updates.
maDispatchToProps - this is callback used to create action closures connected to redux via dispatch. This way Redux store is aware of actions triggered by your component and can update its state accordingly. Your container component will use only handful of actions. It can happen that container component doesn't need to connect any actions, so you would not need to implement this.
If you find yourself duplicating same mapStateToProps/maDispatchToProps across various container components, you should probably reuse same container component on various places of your app and remove such code duplication this way.

Can componentDidMount share data between pages?

I am still learning React and I apologize if this is a stupid question. I am currently planning about the architecture of my simple App.
I am using Next.js for this project
I have a component that calls the third party API for data every 5 seconds. The data is shared among all pages in the app.
If the component that is fetching the data is not on the main/home page. Are there anyways for homepage to get the data it needs from another page?
For example [Below are all pages]
index.js // Plain simple page that displays current weather and top music
http://localhost:3000/
weatherforecast.js //Using componentDidMount every 5 seconds to fetch Weather Data
http://localhost:3000/weatherforecast
musicplaylist.js //Using componentDidMount every 5 seconds to fetch Weather
http://localhost:3000/musicplaylist
The data shown in homepage has to be refreshed every 5 seconds if there are changes to the following data in weatherforecast.js and musicplaylist.js
I had this in mind but I have a feeling that it's not the right way to do it.
In the Homepage.js, include WeatherForecast and MusicPlaylist components to fetch the data. If this is the case, it seems like I am repeating the same principle in every page.
I found out about Redux which store states as a global object. But how does the state know when to update. But before we getting to state, I am still not sure if components on another page can fetch the data without the user accessing the page.
Thanks for reading this question.
For a pure React solution, you need to utilize other lifecycle methods available for React. componentDidMount is a good spot for making API requests, so you're in the right place to start. However, componentDidMount occurs only once, right after the componentWillMount and after the DOM is ready with a complete render of the component. Setting your API call to run at a set interval will not trigger a rerender of the component, no any of it's sub components. Instead, use componentWillRecieveProps to add your interval request logic. After each interval completes, run setState with the new data from the request to update the default state defined in your constructor. As a bonus step to improve performace, follow up with function that returns a bool in componentShouldUpdate. This way you can strictly define how and when and what is causing any and all component re-rendering.
Redux is an excellent solution to take care of what you want to do. Personally always use it in my React projects to manage state. Using Redux, you could make your API calls still occur in componentDidMount, however the call can hook into your Redux store and update your initial state. The frees you up from have to worry about the local state of your component and how to go about conditionally rendering everything else in your app. Plus Redux abstracts other functions you need, like re-running your fetchToAPI in certain intervals, into their own source (known as Action Creators). Action Creators hook directly in the Redux store so that when one is used, the resulting state diff is passed to Redux's Reducers, which in turn update the application global state. Then all that needs to be done is to have all of your components that need re-rendering on global state change to listen for state changes that occur in the Redux store and conditionally re-render based on the diff of the store from prevState => newProps. This can be setup fairly easy using the boolean check in componentShouldUpdate.
Hope this helps! Cheers.
Redux passes the data throughout the connected components via prop, given that a component is mounted whenever it receives new props a new render cycle is initiated so it will reflect your changes, moreover if you dont want to use Redux you can try using the new context api which is easy to implement and will also be suitable for your solution here is a tutorial on how to use it
To pass data between pages in next.js you will have to use Redux. The idea of Redux is to have a single source of truth. In redux you update the state by calling actions. To update redux state you have to create something called action creators which dispatches action to update the state.
Answer to your question as to if components on another page can fetch data without the user accessing the page is that they do not need to access the data. The components are mounted only when they are accessed, so it will fetch the data when they are mounted.
Regarding the state change notification, refer to below image, and hopefully it is worth one thousand of words:
Original article here.

How to communicate UI state changes between React components with Redux?

as far as I understood Redux it is about keeping all state of the UI in one store (to be able to reproduce certain states easily and to have no side-effects). You can manipulate the state via triggering actions which trigger reducers.
I am currently writing a small blog-like app where you can simply create and edit posts. I have a dialog for creating a post, roughly the render method of the App component returns something like this:
<div>
<AppBar ... />
<PostFormDialog
addPost={actions.addPost}
ref="postFormDialog" />
<PostList
posts={posts}
actions={actions} />
</div>
My question is: should the state of the dialog (opened or closed) be part of the state object of the App component? And should therefore opening and closing the dialog be triggered via an action instead of doing something like the following:
onTriggerCreatePostDialog(e) {
this.refs.postFormDialog.show();
}
where onTriggerCreatePostDialog is triggered via some click listener on a "create" button or so.
It seems a little bit strange to me to do it via an actions because is introduces kind of an "indirection".
However, assuming that I want to reuse the dialog for the edit action, I must be able to open the dialog from elements which are deeper in the component structure, for example from a Post component which is a child of the PostList component. What I could do is pass the onTriggerCreatePostDialog function down the hierarchy via the props property, but that seems cumbersome to me...
So int the end is is also about communicating between components which are not in a direct parent-child relationship. Are there other options? Should I somehow utilise a global event bus? I am quite unsure currently.
It seems to me that you are on the right path. The docs can be a bit tricky at first, but I can tell you how my team and I are using the implementation.
To address your first question; if the state is specific to a component then we keep that state with the component. An example of this would be a panel that pages records locally --- nothing else needs to be aware of that behavior. So in this instance we wouldn't trigger a redux action when the page changed, that would be handled internally within the component structure using refs.
Our redux state is comprised primarily of data collected via xhr requests or from a shared state. An example of shared state would be managing a time range among multiple components that use that range to display data. In this instance we would trigger a redux action; update the date state with whatever it was changed to (while also updating some other state items via xhr) and then ultimately that gets back to the components and they re-render.
With that said, triggering actions via refs is totally acceptable, it's just about what the specific use case is.
To address your second question; redux recommends using the Smart & Dumb component concept. So you are right that you would pass a function down the tree for the dumb components to utilize.
We utilize mapDispatchToProps in our connect setup. So basically you pass a function that returns an object of function "dispatchers". You will be able to access those functions directly in your smart component's this.props.
Example of mapDispatchToProps
function mapDispatchToProps(dispatch) {
return {
myAction: () => dispatch(actions.myAction()),
};
}
So that works 99% of the time, but I've run into some corner cases where we do use a global event bus, so don't be afraid to utilize both while attempting to stick to the Smart / Dumb component method as much as possible.
As a side note, I would recommend using reselect to map your redux state to the smart component. You can also find other great redux resources here (there are several things listed that we use).
The state for the dialog should be in the redux store, triggered by actions. whether it should be rendered should be determined by checking that state in the redux store.
App.render() should be something like this:
render() {
const { showDialog } = this.props;
return (
<div>
<AppBar ... />
{ showDialog ? <PostFormDialog ... /> : false }
<PostList ... />
</div>
);
}
where mapStateToProps would be something like state => {{ showDialog: state.showDialog }}
In terms of delivering the action creator, passing it down the props tree is probably the correct way to do it unless you have some good location where it makes sense to have another smart component.

ReactJs: How to pass the initial state while rendering a component?

I know I can pass props while rendering a component. I'm also aware of the getInitialState method. But the problem is, getInitialState isn't quite helping because my component doesn't know it's initial state. I do. So I want to pass it while I'm rendering it.
Something like this (pseudo-code):
React.render(<Component initialState={...} />);
I know I could use a prop to work as the initial state but this smells like an anti-pattern.
What should I do?
EDIT FOR CLARITY
Imagine I have a CommentList component. By the time I first render it, the initial state corresponds to the snapshot of current comments from my database. As the user includes comments, this list will change, and that's why it should be a state and not props. Now, in order to render the initial snapshot of comments I should pass it to the CommentsList component, because it has no way to know it. My confusion is that the only way I see to pass this information is through a props which seems to be an anti-pattern.
Disclaimer: Newer versions of React handle this on a different way.
Only permanent components might be able to use props in the getInitialState. Props in getInitialState is an anti-pattern if synchronization is your goal. getInitialState is only called when the component is first created so it may raise some bugs because the source of truth is not unique. Check this answer.
Quoting documentation:
Using props, passed down from parent, to generate state in
getInitialState often leads to duplication of "source of truth", i.e.
where the real data is. Whenever possible, compute values on-the-fly
to ensure that they don't get out of sync later on and cause
maintenance trouble
You can still do:
getInitialState: function() {
return {foo: this.props.foo}
}
As they will be the default props for your app. But as long as you are using a prop to set a value that presumably won't change, you can use the same prop inside of the render function.
<span>{this.props.foo}</span>
This props won't be modified, so no problem using it each time the render is called.
Edited answer:
In this case your initial state should not be a prop, should be an ajax call which populates the comment list.
To quote the React docs:
Using props, passed down from parent, to generate state in getInitialState often leads to duplication of "source of truth", i.e. where the real data is. Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble
And:
However, it's not an anti-pattern if you make it clear that synchronization's not the goal here
So if your props include a value and an initialValue, then it's clear that the latter is for initialization, and there's no confusion.
See the React docs for code examples.
If you know the state then I would tend to argue that the component you are rendering is not really in control of it. The idea in React is that any particular piece of state lives in only a single location.
After seeing the other answers, and studying a little bit about it, I've come to this conclusion:
If you are rendering React in the client (compiled or not), which is the default approach, you should try to make an extra Ajax call from inside your component to get the initial state. That is, don't use props. It's cleaner and less error prone.
However, if you are rendering in the server (Node.js or ReactJs.NET), there's no reason to make this extra Ajax call for each request.. Besides, it's not SEO friendly. You want the complete page to come as the result of your request (including data). So, as #RandyMorris pointed out, in this case it's ok to use props as the initial state, as long as it's exclusively the initial state. That is, no synchronization.

Categories

Resources