react load local storage at first - reactjs

I have a react app like where I have App.js which includes my Headers and Footers ..
In there I am storing my state to local storage.. After storing I can retrieve it ..
But I am having problem on loading it.. In my browser when I do localstorage['key'] it gives me the data but I am unable to load.
Where should I load it first ?
I have Root.js :
class Root extends Component {
render() {
const { store } = this.props
return (
<Provider store={store}>
<ReduxRouter />
</Provider>
)
}
}
Root.propTypes = {
store: PropTypes.object.isRequired
}
export default Root
and index.js at outer level :
const store = configureStore()
render(
<Root store={store} />,
document.getElementById('root')
)
Where should I load my localStorage ?
Need help . I need to know what is called first in react so that I can make a call to load localStorage there .. If it is not bad idea

You're using redux, so you should read the data as the result of an action.
The simplest way to make this work would be:
Under ReduxRouter there should be a connected component. See docs
In that connected component, add componentDidMount to call an action getStuffFromLocalstorage. See React lifecycle events
In your reducer, get what you want from localStorage and populate the state
It might be an antipattern to do it in your reducer, but it will at least make the redux-flow go around.

I would suggest to fetch the local storage data from the componentDidMount method inside the app.js file.
Please find the official reference here:
https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount
if you wanna update the localStorage data before the component gets unmounted you can use the method componentWillUnmount:
https://facebook.github.io/react/docs/component-specs.html#unmounting-componentwillunmount

Related

How can i share data between non-related components in react js?

I'm quite new with reactjs, and I'm struggling with the following:
I have a Header component (in my App.js file) which contains an AudioPlayer. This AudioPlayer needs to be updated with current value of src (with the path of the song, stored in local) and title. Now, think about something like this:
App.js
function App(){
<Header/>
<Page1/>
<Page2/>
<Page3/>
...
<SomePage/>
...
<Footer/>
}
Header.js
import HeaderLogic from './HeaderLogic'
funtion Header(){
const {property1, property2, ..., path, title} = HeaderLogic()
//In HeaderLogic I want to get path and title, set in SomePageLogic.js
...
return <>
<AudioPlayer
src={path}
title={title}
/>
...
</>
}
SomePage.js
import SomePageLogic from './SomePageLogic'
import songPath from './somePath/songPath'
function SomePage(){
const title = 'songTitle'
const {property1, property2, ..., propertyN} = SomePageLogic(songPath, title)
//In SomePageLogic (or maybe here) I want to set path and title of the song,
//in order to be used from the HeaderLogic component
return <>
...
</>
}
I'm not sure useContext could be fine in this case, since I want to share data between unrelated components... Of course, the Header should rerender when it detects the song has been set. Should I use some kind of subscription pattern?
Any hint?
Thank you very much!
you can use Redux for storing your states. Basically React Redux is kind of a store where you can store your state and whenever it get updated it directly render html. you can access store state anywhere by using useSelector in hook, it get updated value whenever it changed by some other component
No need for any subscription pattern and definitely not using localStorage - context is exactly used for your usecase: sharing state between unrelated components.
So for instance, I want to share selected menu between the header and the Page1 somewhere below, you'd create a context with createContext(), export it's provider, wrap the children, and then you share that state between all components you set as children. Example:
const defaultSelectedMenu = 'a';
export const MenuContext = createContext({ selectedMenu: defaultSelectedMenu });
export const MenuProvider = ({ children }) => {
const [selectedMenu, setSelectedMenu] = useState(defaultSelectedMenu);
return (<MenuContext.Provider value={selectedMenu, setSelectedMenu}>
{children}</MenuContext.Provider>)
}
And then in your app.js:
...
<MenuProvider>
<Header />
<Page1 />
</MenuProvider>
<Page2 />
...
Now, your Header and Page1 components can access the MenuContext through useContext(MenuContext) and have access to the state and the mutator.
This was just a simple example but the same logic applies to any logic you want to share, heavy computation, API calls, you name it. You define the implementation in the <Provider> and then consume the implementation by accessing it through useContext
You can use localStorage.
Basically, it'll store your desired value in the browser. So, you can access it from anywhere within the application.

Is there any way I can see relationships between fields in Redux store and React components?

The goal is take control over other application and I already getting data from redux store. But i wanna see which component using which field from Redux store.
Let me show in example:
Target application
const App = props => (
<React.Fragment>
<AppComponents/>
<MyImportedComponent dispatch={props.dispatch} state={props.state} />
</React.Fragment>
);
const mapStateToProps = state => ({ state });
export default connect(mapStateToProps)(App);
In this example i already can take control over the application but i cant see which components related to which field from Redux store. So i can realize it only when i dispatching actions and updating store.
Could I access some data from application like following?
{
AppComponent: {
connect: {
mapStateToProps: [{
...someFieldsJustHere
}]
}
},
AnotherComponent: {
...somethingSimilarToPreviousOne
}
}
I already try to use HOC and decorators but i cant access such data. Now playing with react-test-renderer and mocking store.
Updates:
With react-test-rendered i got access to components props including props from connect HOC but now i don't know yet how to get reference to real component from DOM tree.
Example
const component = renderer.create(
<Root>
<App />
</Root>
);
console.log('rendered: ', component.toTree());
Any ideas?))

Access React context value from redux-saga function

I have some variables which are controlled by React Context through React.createContext() with Provider and Consumer component. I'm also using redux-saga, so my question is are there anyway to access this context value in redux-saga function. I'm looking for something like "yield select" statement that works with redux-store.
Anyone who know it please explain to me. Thank you in advances.
P/S: Currently, I pass context value to action object payload when dispatch an action. So in redux-saga, we can use it in action parameter. I don't know whether it's the best practice.
EDIT: There is now a package that allows you to grab context easily, react-outside-call
You can keep an outside reference of your provider component, and grab the state from that.
Something like this...
Provider component
class AppProvider extends Component {
state = {
number: 10,
}
render() {
return (
<AppContext.Provider value={this.state}>
{this.props.children}
</AppContext.Provider>
)
}
}
Apps main entry file, or where ever you reference that provider instance.
let appProviderRef
export const getProviderState = () => appProviderRef.state
ReactDOM.render(
<AppProvider ref={ref => appProviderRef = ref}>
<App />
</AppProvider>
, document.getElementById('root'))
You can now grab the state from within your redux sagas (or anywhere you want) synchronously calling getProviderState

How to keep React new Context API state when routing between Components?

Summary:
1) Do you know how to keep the state of a Context Provider present when it is mounted/unmounted through routing?
2) Or do you know a well maintained Flux implementation that supports multiple separated stores?
In detail:
Besides React components own state I've been using mostly redux so far. Besides not loving the idea of having every state managed globally, even though it might only be relevant for a subtree, it also becomes an issue for my new project.
We want to dynamically load components and add them via routing to the app. To be able to have components ready for plug and play, we want them to take care of their own state (store it, request it from the server, provide a strategy to modify it).
I read about how to dynamically add reducers to the global store with redux, but I actually find the approach of Reacts Context API much nicer where I can encapsulate some state in a Provider and can consume it wherever I need it.
The only issue I have is, that a Provider and a Consumer are React components, so if they are part of a component, that is mounted and unmounted through routing, the state that might have been created or fetched once, is gone.
It seems to me that there is no way to solve that, besides temporarily storing the state in the localstorage or on the server. If there is, please let me know!!!
If there shouldn't be a better solution:
I also thought about a more original Flux implementation that would allow multiple stores, which could be encapsulated with the relavant component subtree. But I haven't really found any well maintained Flux implementation besides Redux. Mobx being the exception, but I really prefer the reducer solution of Redux over the observable solution of Mobx. So again, if you know a multi store Flux implementation that is well maintained, please let me know!!!
I would be really happy about some feedback and hope you can point me into a direction that is more satisfiying than dynamic reducer Redux or temporarily persisted Context state.
Thanks a lot in advance!
Sorry that it's quite a late answer
Are you using React Router?
The state should be persisted and it shouldn't clear if you are navigating correctly. There should be no page reload as this will cause the state to clear.
Here is an example:
import { Router as RootRouter } from 'react-router-dom';
import Router from './routes/Router';
const App = () => {
return (
<MyContext value={useReducer(myReducer, initialState)}>
<RootRouter history={browserHistory}>
<Router />
</RootRouter>
</AuthContext>
);
}
import About from '../components/About';
const Router = () => {
return (
<Switch>
<Route exact path='/about' component={About}></Route>
</Switch>
}
On your main home component, you have to use a Link or Navlink to "switch" between components. Therefore, you'll have something like...
import { Link } from 'react-router-dom';
<Link to="/about">About</Link>
This will navigate you to the about page in which you can still access the context stage where nothing is cleared.
So I figured out a way to work around the problem with Context (first question): I store the state of the Provider component in a variable. That way, when that component is mounted again, it uses the "persisted" state as the initial value for it's state.
let persistedState = {};
const Context = React.createContext();
export class Provider extends React.PureComponent {
state = { ...persistedState };
updateState = (nextState) => this.setState(nextState, () => {
persistedState = {...this.state};
});
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
);
}
}

How to pass props to react-router 1.0 components?

Please note, that although the question itself is largely a duplicate of this, it concerns a different version which should support this. The linked question already accepted an answer on an old version
I'm pretty confused about what the intended workflow is.
Let's say I have a menu system where clicking on each item uses react-router to navigate to an area which pulls some data from the server.
url: yoursite/#/lists/countries
----------------------------
Billing Codes | <<Countries>> | Inventory Types
---------------------------------------------------------
Countries:
---------------
Afghanistan
Azerbaijan
Belarus
with routes something like
Route #/lists component: Lists
Route billing-codes component: BillingCodes
Route countries component: Countries
Route inventory-types component: InventoryTypes
I don't want to preload data from the server until an area is navigated to, so in my Countries component's on componentWillMount I fire an event (I'm using reflux but...whatever) that triggers a store to do an ajax request and update itself with the current list of countries.
Now the Countries component reacts to that change in state by updating the countries in its props. Except - reasonably - that generates an invariant error because I shouldn't be updating props on a child component, I should update it at the top level. But the top level is the router itself so now I'm just lost - where am I supposed to listen to changes and update props from?
(Cross-posted to the issue tracker as I think it needs some clearer documentation)
Reading the react-router 0.13 -> 1.0 Upgrade Guide and this example led me to the following:
{ this.props.children &&
React.cloneElement(this.props.children, {newprop: this.state.someobject }) }
Instead of including the child components directly, we clone them and inject the new properties. (The guard handles the case where there is no child component to be rendered.) Now, when the child component renders, it can access the needed property at this.props.newprop.
The easy way is to just use this.state, but if you absolutely have to use this.props then you should probably extend Router.createElement.
First add the createElement prop to your Router render.
React.render(
<Router history={history} children={Routes} createElement={createElement} />,
document.getElementById('app')
);
Wrap all of your components in a new Container component.
function createElement(Component, props) {
return <Container component={Component} routerProps={props} />;
}
Your Container component will probably look something like this. Pass an onLoadData function down to your component.
import React from 'react';
import _ from 'lodash';
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { props: props.routerProps };
}
onLoadData(props) {
var mergedProps = _.merge(this.state.props, props);
this.setState({ props: mergedProps });
}
render() {
var Component = this.props.component;
return <Component {...this.state.props} onLoadData={this.onLoadData.bind(this)} />;
}
}
Then from your loaded component, when you get your data back from the server, just fire this.props.onLoadData(data) and the data will be merged with your current props.
Read the Router.createElement Documentation

Resources