I have a state varible for color in a canvas file
const [selectedColor, setSelectedColor] = useState('#FFFFFF');
and I want to access it from a sidebar to put a colour picker in it. Is there a way I can set the variable from another file and have it update on the screen like a normal state variable? Thanks.
There are a number of possible solutions and I would say that it depends on your component tree (i.e. how is your application structured).
If your Sidebar and Canvas component have a shared parent component (i.e. a component that has Sidebar and Canvas as its children) then the easiest way would probably be to use a concept called lifting state up whereby you move the state logic to that shared parent component that passes state down to its children via props. Read more about lifting state up in the official React documentation.
An alternative approach is to work with React Context, which is already built-in in the library. This requires more set-up so I would suggest starting with lifting state-up if possible. Read more about Context here.
There are also other solutions such as working with state management libraries (e.g. Redux, Jotai,...) but they are too complicated for this simple use case.
Related
I need to get a child component position in a tree in my React app to make a 'tour/guide' for my application. if it was vanilla js, I was able to easily get the target node using document.querySelector() but since in react we have to use refs to get access to the element, and it's not a good way to use refForward in many child components to approach the target one from the grand parent component, what is the best solution to get properties of a child component in a tree?
I think one possible solution is saving target elements' position in a global state manager like context or redux, but since the position is changing frequently, it would cause some critical performance issues in the app.
Thank you in advance.
I have a parent component that has state and a child component that uses the youtube-react api to create a video player. The child component contains both state and methods that are used to work on the video player (e.g. event handlers).
I want to ask if should I separate out the child component by making it a stateless functional component? I can do this by placing all the methods and state of the child in the parent component and then pass all relevant methods/data down to the child via props.
My concern with separating the child component is that will make understanding how everything works confusing. Also, it will result in a huge parent component as the parent component already contains methods and state for other child components.
I think it all breaks down to personal preferences. I like to write components which are reusable and handle all the logic by themselves, so that I can use them as often as possible. This could result in some components get bigger then others.
I think a good starting point is here: https://reactjs.org/docs/thinking-in-react.html
I created a layout component for my react app, and I wanted to dynamically update the side bar and navigation bar on route change.
I can use redux, but all of the state and methods will be available at all times, even if i don't need them.
I also looked at the new react context, but it has the same problem as redux.
With react router, it looks like i'm just mounting a new sidebar or navigation bar.
Is there a way to dynamically provide new state and methods to my layout component?
(replace the state with a different one, or multiple new once: apple --> orange)
React router looks like my best option, but I can do the same thing by just including the sidebar and navigation bar with each new route.
Dynamically adding links is not a problem, adding a button that affects the newly mounted component is the problem. The navigation bar and side bar lives in the parent component, so they need to know all of the states and methods.
Thanks,
Edit:
Example:
- Home - About - Contact
No problem, with link. I can just replace the link components with any other component with a switchComponet method.
Stop - Speed-Up - Help
These are all buttons. Now I need to add their methods and state to the Layout component. Is the app grows, more state and methods will need to be added to the top component.
I can place all of them in redux, but all the state and methods are always available. I probably have the wrong impression about redux, I'm thinking that it might take up a lot of resources, but I might be wrong.
My guess is that by "state and methods" you mean the mapStateToProps and mapDispatchToProps arguments of the react-redux connect function in your layout component.
If that's the case then you have reasons to be concerned about putting the logic of all possible content of your layout in there.
I think your problem is that you're assuming that you have to connect only the top container to redux when it's not the case.
You can connect your layout component to deal with the nav and side bar and at the same time having components nested in your layout component and connected to redux with their own store keys (part of the store state) and actions.
This way you don't need to add all store states and action needed for each layout content. Each layout content will stay close to its logic.
That's actually one of the purposes of redux.
I'm hacking with React/Redux and have been building lots of container and components.
However I recently encountered a design choice I made that made on of my Elements look like this:
My question is is this design OK? Basically I am struggling how to pass the Redux Actions down to the Button, since the button is a few levels deep. I could keep passing the actions down component to component from the HeaderContainer, but if the DOM got deeper it would just get worse and worse.
I feel like this design is WRONG since a presentational component is calling a container component.
Any thoughts?
You have three options:
First is to directly connect the button component to the store and let it be both container & presentational component. Simple and effective.
export default connect(mapStateToProps, mapDispatchToProps)(ButtonComponent)
See an example from the creator of Redux here (the 4th post)
Second is to create a container to wrap the button and let the button be only presentational - your current implementation. Very good layered architecture, but overengineered at this point for me.
Third is to pass the action down from the HeaderComponentContainer to the ButtonComponent.
I would go for the third one if the button is no more than 2 levels deep, since you already connected your HeaderComponentContainer and as a parent it is its responsibility to determine what functionality its children should provide (they only present, right?).
PS. You can use React's context to pass actions / properties arbitraly deep in the hierarchy without explicitely doing it for each component.
Suppose we have two sibling react components called OldContainer and NewContainer. There is a child component inside OldContainer that contains a <video> tag, and the video is currently playing.
The user can now drag the child component (with the video) and drop it in the NewContainer, and they expect the video to keep playing while it's being dragged and after being dropped.
So the video appears to stick to the mouse position, and when dragged and dropped in the new container, it animates to its new position (again, it doesn't get paused).
How would you implement this? Can we implement this in a pure way (in line with the spirit of pure functions)?
Clarification: I could have used some other element instead of a video tag for explaining this problem. A NumberEasing element would be a better example, since it would require the props and state of the component to be preserved during and after the interaction.
Update 1: Code examples obviously would be nice, but what I'm mainly looking for is just a general description of how you would approach this problem in a "functional" way. How do you keep your view code simple and easy to reason about? Who handles the drag-and-drop gesture? How do you model the data that's fed into the views?
Take a look at this library : react-reverse-portal
What is it that you want to preserve? Is it Javascript objects that the component holds as state, or is it state in the DOM (like how long a video has played, or text selection in an input box)?
If it's just Javascript objects as state, you're better of moving the source of that state to another service (something like Flux). That way, it doesn't matter if the component gets recreated because it can be recreated with the state that was there before.
EDIT
The way to keep your view code simple and easy to reason about is to not keep state inside your components. Instead, all data that the component needs should be passed into the component as props. That way, the component is "pure" in that it renders the same output given the same props. That also makes the problem of wanting to reuse a component instance a non-issue, since it doesn't matter when the same input gives the same output.
For drag and drop, I'd suggest looking at: https://github.com/gaearon/react-dnd.
How you model the data you pass to view components is up to you and the needs of your application. The components shouldn't care, they should just expect to get data passed as props, and to render them. But the popular approach to dealing with this is of course Flux, and there are many libraries that implements Flux in different ways.
SECOND EDIT
Regarding if you have a subtree with hundreds of components that you want to move: I'd still start off by making the state external (pure components), and render that tree in a new place. That means that React will probably recreate that entire subtree, which is fine. I wouldn't deviate from that path unless the performance of it turned out to be horrible (just guessing that it might be horrible isn't enough).
If the performance turned out to be horrible, I would wrap that entire subtree in a component that caches the actual DOM tree and reuses it (if it gets passed the same props). But you should only do this when absolutely needed, since it goes against what React tries to do for you.
THIRD EDIT
About gestures: I'd start out with listening to gesture events in componentDidMount, and in the event callback call setState on the component with the coordinates it should have. And then render the component in render with the coordinates given. React won't recreate the component when you call setState but it will re-render it (and diff the output). If the only thing you changed was the coordinates, it should render fast enough.
If that turns out to be too slow, like if the subtree of that component is huge and it becomes a bottleneck to recreate the subtree of vDOM, I'd reposition the DOM node directly in a RAF-loop outside of Reacts control. And I'd also put a huge comment on why that was needed, because it might seem wierd for some other developer later.
Create a new variable using const or var. Put the instance of data using rest spread operator, update the necessary data to pass and send the data to the component without mutating the state of component.
Just like:
const data = {
...this.state.child,
new_data : 'abc'
}