I don't want to use redux because there's too much boilerplate. So I am looking for a way to share a global state between components. Is it ok to pass the whole state of the App (root) component?
I have no issue with it so far but there must be a hole down the road, is there?
<HashRouter>
<App />
</HashRouter>
<Switch>
<Route exact path='/' render={props => <TheListForm appState={this.state} app={this} />} />
<Route exact path='/myvideos' render={props => <MyVideos appState={this.state} app={this} />} />
</Switch>
So in my child components I have "this.props.appState" which contains the equivalent of the redux store and I can update it simply by doing:
this.props.app.setState({name:"bob"});
If you want a smaller, with less boilerplate and with a lower learning curve state management library, you could check out mobx. You want to use a state management library, if you component exceeds more than a few child component, because your app will rerender everything on every change. With this.props.appData.setState and a form your while app would rerender if the user types something. It also breaks the react one way data flow concept.
Imagine that you build a large scale project and there are so many hierarchies.
A includes B, B to C, ..., Y to Z.
If you want to pass the props from A to Z, you must set properties of all components from B-Z.
In that case, Redux is very useful and you only correct 2 components A and Z.
And also you can implement the bi-directional data flow with Redux.
https://rootzjs.org/ you should give it a try with this one. dead easy to use.
Related
I am having a Server Side Rendered React app where I use HashRouter for react routing(v5). My Routes look like this
<HashRouter basename="/">
<Layout {...config} />
</HashRouter>
<Switch>
<Route exact={true} path="/" component={LPComp} />
<Route exact={true} path={this.props.siteBanner.Red} component={bannerPage} />
</Switch>
When I hit localhost:8888/parent/ and once it get loaded and if I hit localhost:8888/parent/banner in the same window the bannerPage component renders fine.
But I hit localhost:8888/parent/banner directly(consider in a new tab), then the component is not rendered properly.
Any ideas why this is happening?
Also to add on when I hit localhost:8888/parent/banner I can see LPComp(default route) also being loaded and then it disappears suddenly and the bannerPage component renders improperly.
Thanks in Advance
The behavior is making sense, since your routes is based on a prop/state this.props.siteBanner.Red. So the first thing is to put a console.log once you enter this component.
console.log(this.props.siteBanner.Red)
In your first case, you reach this component from its parent, this way the props mostly likely is resolved.
In your second case, you reach it directly, of course also from its parent, but most likely there's no time for the props to get resolved quickly. Couple of possibilities
useEffect is to update this variable
mouse click is required to get a value
setTimeout is used to defer
callback is used to get this variable
You can say there's 50ms delay in getting this prop resolved, but you need to dig out why yourself. Dynamic route is more advanced thing, it's easy to have permanent route.
Thank you all for your timely response, I was able to solve that issue by setting location=(req.url) from the server side configured static router. Going through this example I got the bigger picture I was missing.
https://medium.com/javascript-in-plain-english/server-side-rendering-in-react-redux-ab0af31c9c4b
I would like to pass in some props from the router to the components
Something like this:
<Route component={Foo} some_prop={12}/>
Is there any way to do this with the latest react-router? I know it was not possible (without using a wrapper) pre 1.0.
If you're passing them directly to the <Route /> component like that, it's now possible to do it exactly the way you're suggesting:
<Route foo="bar" />
Will give you access to the foo prop on this.props.route.foo
Via: https://github.com/reactjs/react-router/blob/master/docs/Troubleshooting.md#passing-additional-values-into-route-components
As a side note: if you're using something higher level like <RouterContext /> it is still necessary to use a data wrapper component of some kind, unfortunately.
I am having trouble understanding some ReactJS and Redux principles,
In Redux we have a store and a set of reduceres that give your final state ( this part I get).
A Component receives props from their parent component, in case of Redux it passes the full state down with the Provider Component.
Now, lets assume this use case, I have my app state something like this :
auth : { name,id, ..etc} -> this is actually a JWT Token with a set of claims...
I am building a Container (Page) to be able to edit user profiles, the catch here , and where I am having trouble, I also want this page to handle a arbitrary user edit (in case admin is editing a account).
I am rendering my Page by using redux-router like this :
<Route path="/user" component={RequiresAuth(UsersPage) } >
<IndexRoute component={RequiresAuth(UsersOverview) }/>
<Route path="/user/overview" component={UsersOverview} />
<Route path="/user/account" component={AccountManagement} >
<IndexRoute component={RequiresAuth(AccountManagement) }/>
<Route path="/user/account/:userid" component={AccountManagement} />
</Route>
So reading the docs, I assume my props will have a userid which will override my default user if present.
Questions:
Is this approach correct? The Route Handling?
If I pass a userid param on the route, how do I proceed to load the user info and where? The way I see it, I need to dispatch an action, but I am not sure where to set the state , if on the store, or the component.
Also, Where would I load my user information? (constructor comes to mind)... or should it be in WillMount/WillReceiveProps?
Thank you.
If you really have a hard time to understand React/Redux principles i suggest you to try this tutorial :
https://github.com/happypoulp/redux-tutorial
It helped me a lot when i first started with React/Redux. By the way it's a bit hard to really answer your question because you re asking specific questions on a really specific case :)
I have four components: Panel, PanelHeader, PanelBody, PanelFooter they are composed as following:
<Panel>
<PanelHeader>
some title
</PanelHeader>
<PanelBody>
<div>
main content
</div>
</PanelBody>
<PanelFooter>
footer content
</PanelFooter>
</Panel>
I also have multiple routes, where I want to see that Panel, but with different content.
An obvious solution is to create components for each of routes and each of those components will have their own Panel.
But in my case I want to add some morphing animation between routes (change the height of panel, slide body, fade footer etc.). To achieve this I need to render all the contents to exactly the same Panel, PanelHeader, PanelBody, PanelFooter instances, so the solution above won't work.
So I need to split my route component into three components for each PanelXXX and the problem is that those components need to react on events of each other.
There are the following points so far:
I can't create another one mediator component to control those three partial components, because I will not be able to access its API till it will be rendered (so I can't implement getter methods e.g. getHeader()).
I can connect them all to redux, but it seams too complicated.
Another one solution is to create non-React object to share the state, but in this case I will need to clean up after this object to overcome memory leaks. The connection with redux will also be tricky. This approach looks not so clean to me.
I can also cheat with transparent background, so that I can have one Panel but multiple PanelHeaders etc. But in this case I will need to spread the knowledge about animation to all the child components.
Does anybody knows any other approach to do that in React? Or should I choose one from the points above?
I think that the scenario you are describing and the questions you pose are the exact rationalizations for using Flux. Redux is one option. We used a plain vanilla Flux implementation using the original Facebook library and we have had great success. It has a steep learning curve, but once you get your head around it, issues like the one you are facing just fit right in to the infrastructure.
Sounds like you could benefit from using this.props.children.
Router
<Router history={createBrowserHistory()}>
<Route path="/" component={App}>
<IndexRoute component={DefaultView} />
<Route path="foopath" component={FooView} />
<Route path="barpath" component={BarView} />
</Route>
</Router>
App.js
...
render: function() {
return (
<Panel>
{this.props.children}
</Panel>
);
}
...
DefaultView.js
render: function() {
<div>
<PanelHeader>
FooHeader
</PanelHeader>
<PanelBody>
FooContent
</PanelBody>
<PanelFooter>
FooFooter
</PanelFooter>
</div>
}
You can read more about React's children here.
I have simple main.js file:
import React from 'react';
import ReactDOM from 'react-dom';
import App from "./components/app";
ReactDOM.render(<App />,
document.getElementById('appContainer')
);
The App component defines routes:
render(){
console.log('app', this.state.current, this.state.global);
return (
<Router>
<Route path="/" component={Template} current={this.state.current}>
<IndexRoute component={GlobalList} global={this.state.global} />
<Route path="current" component={CurrentList} current={this.state.current} />
<Route path="item/:item" component={ItemDetail} />
</Route>
</Router>
);
}
I use the re-base package to communicate with my Firebase database. This library doesn't allow to do syncState for one endpoint more than once for all application. This is a reason, why I get those data in App component and want to pass them to Routes. And this is a problem.
This console.log in render method is called 4 times. First two give empty data, third gives first endpoint and forth second endpoint. But Routes are not updated. I can see in Template element, that render method is called also 4 times, but every time props.route.current is an empty array, even if in App this.state.current is array with length > 0.
I would appreciate any hints how to solve this problem. if there is any other way to make it, I would love to read any good practices hints. I use newest versions of libraries, ES6 and webpack/babel to build.
Sometimes it is good to read all library documentation.
Thanks for #TylerMcGinnis for his patience and not using hard words :)
The solution for this problem is using bindToState method, if you want only bind changes to state, but not to post changes to Firebase. It was my case - only one component needs to sync changes, second one needs only listen to changes made by first one.