I am new to web development and was trying my luck with React.js.
I started exploring the Context API where I realised that re-renders (if mounted)/update happens when a component is subscribed to a context and the value of the context is changed.
So I tried understanding the situation by writing some snippets, here is the full code-base.
In the example, I created two components (BucketVegies.jsx and BucketFruits.jsx) with a common parent (Fridge.jsx)
Then I created two context, ContextVegies and ContextFruits with their own providers and consumers. I exposed the consumers using custom hooks (useVegiesContext and useFruitsContext)
My Question is:
Why are sibling components re-rendering upon changing the values in either of the context? From what I read, only the component subscribed to a context must re-render/update when only its context values is changed. (In our example we "add" an item on button click hence change of value)
Related
When I've been developing in pure React.js, I was used to store some data into Redux and set some component to listen to changes in Redux (with useSelector (source). But now I am doing facing the same problem but in different technology. In Remix there's no useSelector with Redux. Yes there is possible to use useState but it have to be under one parent compopnent but I don't have this structure. So is there any solution to force component to re-render when some independent state changes?
Thanks
I've tried to call some function to force re-render but that's not 'nice' solution. I've even thinked about storying data into localStorage/cookies but when they change, components doesn't update (I understand why it doesn't force re-render but I've tried it...).
Redux should still work normally even with Remix, as it's just a state manager. It's entirely possible that all you have is a configuration issue with Redux (I personally dislike Redux for how needlessly complex it into use)
You could try React's own Context for storing state that could be used by several components. Other proven state managers are the likes of jotai or zustand.
Even regular state could work because there's always a root component in remix: i.e. root.tsx.
It's hard to understand what you're trying to achieve. Other ways to update various parts of the UI is using nested routes and . You can access parent and child page data with useLoaderData().
I am building a web app where redux is configured and app is fairly large.
Now I want to store some user preferences which will be available as part of an API respopse.
As this data is required to the majority of components I am planning to store data in the context and wrap application using the context.
I have Few questions regarding approach.
Will considering context impact the performance?
As Redux is already configured which internally uses the Context. So should we continue to use redux for user data.
Is it good practice to use Redux and Context together.
Context and Redux are very different tools that solve different problems, with some overlap.
Context is not a "state management" tool. It's a Dependency Injection mechanism, whose only purpose is to make a single value accessible to a nested tree of React components. It's up to you to decide what that value is, and how it's created. Typically, that's done using data from React component state, ie, useState and useReducer. So, you're actually doing all the "state management" yourself - Context just gives you a way to pass it down the tree.
Redux is a library and a pattern for separating your state update logic from the rest of your app, and making it easy to trace when/where/why/how your state has changed. It also gives your whole app the ability to access any piece of state in any component.
In addition, there are some distinct differences between how Context and (React-)Redux pass along updates. Context has some major perf limitations - in particular, any component that consumes a context will be forced to re-render, even if it only cares about part of the context value.
So, yes, you can use them both in the same app, in the same way you can use a hammer and a screwdriver together on the same construction job.
For more details, see my posts:
Why React Context is Not a "State Management" Tool (and Why It Doesn't Replace Redux)
React, Redux, and Context Behavior
A (Mostly) Complete Guide to React Rendering Behavior
Will considering context impact the performance?
Since you want to share user preferences that (I guess) do not change often, you could use a React context to share that data.
But performance issues arise when you put multiple different data in one React context that update at different rates. This is because every component that uses the context will be rerendered even if the part of the context it is interessted in did not change. In this case you can split the context and use one context for each part of the data.
Since you want to use the context to share an application state, you should use Redux. In Redux you use selectors to select a part of the application state. This useSelector hook is implemented in a way that it only triggers a rerender of the component if the selected part changes. You can even pass it an equality function if you want to change the way state change is detected.
As Redux is already configured which internally uses the Context. So should we continue to use redux for user data.
I would say: yes, continue with Redux.
Since you already use Redux you should not spread your application state management over different concepts. Put the user settings in the Redux store (like any other application state) and don't handle them special.
Is it good practice to use Redux and Context together
Well, Redux is based on the React context. So if you use Redux it is already a good practice.
If you mean using both for application state management, I think you should go the Redux or the React context way. Mixing them makes it harder to understand where state is managed.
After reading reacts lifting state up, it made sense how shared state was held by the parent and it would then pass it as props and re-render as needed. However with redux we can have state in the store. Then is it okay to violate the top down data flow and have sibling components interact via redux? Or they should still update the parent state and have the parent re-render them?
Reading the question and answer as of when I post my answer here, I'd like to further add to Bryan's statement using the official Redux style guide:
Prefer having more UI components subscribed to the Redux store and reading data at a more granular level. This typically leads to better UI performance, as fewer components will need to render when a given piece of state changes.
For example, rather than just connecting a <UserList> component and reading the entire array of users, have <UserList> retrieve a list of all user IDs, render list items as <UserListItem userId={userId}>, and have <UserListItem> be connected and extract its own user entry from the store.
This applies for both the React-Redux connect() API and the useSelector() hook.
If siblings are interacting via Redux, the communication is still top down (because they aren't communicating with each other — they're communicating with Redux).
Sibling A dispatches a redux action
Some reducer updates the state
Sibling B updates based on the new state
Using connect from react-redux eliminates the need to manually pass props down through an entire chain of components.
Ultimately, where and how you manage state in an app depends on a lot of different factors. There's no right answer here. I've seen both strategies used within the same app.
I'm new to React, so forgive the newbie question.
I've got a plain ol' JS object that wraps a WebSocket and exposes state based on the messages it's received over the socket, e.g. the current set of messages in a chat. In Angular or Polymer (or WinForms and WPF), when new data comes in, I'd send a notification using a standard protocol to let data bound clients know that the state has changed and re-rendering would happen for those clients.
I'd do the same thing in this case by extending React.Component in my WS wrapper class, except that it's got no UI (it's just a cache of the state gleaned from the messages flowing over the WS), so it would return null from render and I'm not clear on whether it stays in the DOM or not at that point. Further, I'm not sure how to make UI from a parent or peer element of the WS wrapper object update as it's state changes.
What's the React way to have a data-only component? I'm trying to get my head around React before I dive into Redux, so hopefully the answer here doesn't require picking up a Flux implementation.
Thanks!
Sounds like the wrapper JS object should be the App "global" state. Regardless of where you contain it in React (a top-level component with vanilla React, or a store in Redux).
Assuming that you put it as the state of a top-level component, then when new data comes in, all you need to do is setState(newData)
All UI driven by this data should be described within that top-level component that holds the state. All children components can be read-only.
When the top-level component changes its state, all children will be re-rendered with new read-only props.
I am converting a jsp multi-page app(mpa) into a React single-page app (spa). In the mpa, the back button worked and the form retained its state.
In my new React app, the back button works but the form does not retain its state.
Question: is there a trick to make my form retain its state after "backing" to it (in an spa).
Here are the two solutions I came up with:
Encode the entire form state into the url. Then update the browser history with an updated url every time the form changes. But, this seems like a huge pain in the butt.
Modify the structure of my app such that the form in question (a React Component) stays mounted (and just use the css visibility or display property to show and hide). But, in a large app, leaving every page mounted in the DOM seems like it might lead to performance problems.
By the way, I am using popstate and the browser history api to achieve SPA behavior (i.e. i have rolled my own router) as described here.
Hopefully someone can propose a solution that is better than my two solutions. Thanks.
I ended up using something similar to Wylie Кулик's answer with a few changes:
I didn't want to switch to Redux for just this one use-case. So I used the component state of my top-level component (i.e. a component higher up the tree).
I cached the form's state on the form component's componentWillUnmount and restored the cached state on componentDidMount.
I passed the cached state as a prop from the higher component to the child component.
It ended up being a very small amount of code and is working like a charm so far.
Use Redux to have a state store which transcends any particular component. Then in your component, as part of the form submission process, dispatch an action with payload of all of the form data. This should be cached on state and then when the component is remounted by your navigation structure, it should have access to this cache via Reduxsconnectfunctions mapStateToProps method. You can repopulate your form from that.
It's not clear from your question whether or not you are submitting the form in the traditional old way. I would use e.preventDefault in the handler instead, and have all the form data on the component's state, this can be sent to Redux's state store as described above, and Ajaxed off with superagent or similar. At the same time it can be cached.
Redux: http://redux.js.org