I have 2 sibling components home and history where home has the following function
//home
function handledata() {
const key = uuidv4();
localStorage.setItem(key, JSON.stringify(formdata));
}
I need to access local storage in the sibling history component so how do i access this key variable there
//history
const [items, setItems] = React.useState([]);
const handledata = () => {
localStorage.getItem(key);
};
Complete code of both files https://github.com/Megahedron69/testrep
You're best option is to decouple localstorage from both the components & make a it a separate module or a class. Then you can access it in both the files.
Pseudocode
class LocalStorage {
setItem(key, item) { ... }
getItem(key) { ... }
}
If you don't want to do that - Lifting the state up is the best possible solution when want to share data between sibling components.
Make a parent component of home & history & use localstorage there.
You don't need handledata function in that case.
You can just access localStorage without it:
const data = localStorage.getItem(key);
// use this data any way you want in the component
Ways to share data between states:
The parent component.
Localstorage
Global State management
Local storage is not recommended for this stuff and in your case global state doesn't make sense. Parent state is better in your case.
There are multiple things you can do:
Generate key in parent and share it in both components
Create a state in parent component in parent and then set that state in history
Related
Having a hard time trying to figure this out.
I Have 2 Components
A filter component & A table view component
A enhanced view of number table view with more info and functionality
From component 2 i want to go back to component 1 but have the filters still in place?
How can i acheive this?
I've tried
this.props.history.push('/1');
It goes back but doesn't keep the filters?
export default class FilterComponent extends React.Component {
constructor(props) {
super(props)
this.state = {name:[]}
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/todos")
.then((response) => response.json())
.then(
(data) => data.map(e =>
this.setState({name:[...this.state.name, e.id]})
))
}
onTrigger = (event) => {
this.props.parentCallback(event.target.value);
event.preventDefault();
}
render() {
if(this.state.name.length < 1) {
return (
<div>
<p1> Loadings</p1>
</div>
)
} else {
return (
<div className="contactfForm">
<select onChange={this.onTrigger}>
<option> ID </option>
{this.state.name.map((result)=>(<option title={result}>{result}</option>))}
</select>
I guess you are rendering the filters twice, inside component1 and again inside component2. If you want to navigate and preserve the state, you have two react-based options, and a JS one:
MOVING FILTERS OUTSIDE ROUTER SWITCHER
If you render the filters outside the Switcher of the router, when changing route only the component1 and component2 will rerender, but not the filters.
STORING FILTERS STATE IN A GLOBAL STATE
If rendering the filters outside the Switcher of your Router is not feasible (Because maybe the filters are not rendered in every page of your app) you could save the filter state in a global state (Using for example, React Contexts, see https://reactjs.org/docs/context.html; or Redux).
If you use React Contexts, you could create the provider ouside the router, and inside the Filters component retrieve and modify its values. This way you will mantain the state between components.
SAVING FILTER STATE IN LOCAL STORAGE
If you want to preserve the state also when refreshing the page, you could store the filter state in the Local Storage of the Browser. Every time the Filters component is rendered, you would retrieve the value from the Local Storage, and every time the filters are modified, you would save it. That will also make that when changing the page, as the Local Storage is mantained, the filter state is mantained too.
In my vue application I have a component page that contains five components. I also use vue composition api.
each component is lazy, it resolve when the component is in the viewport. because of that I need to write the logic only inside the component. (not in the parent).
so far so good, but two of components inside product.vue depend of the route params value. say /product/2.
the product.vue looks like that:
<intro> -> just a raw text (no need to fetch from the server, not need to wait to load)
<foo> -> need data from the server base on the productId from the route.params.
<txt> -> just a raw text not need to get the data from the server
<bar> -> need data from the server base on the productId from the route.params.
Important notes:
In case I don't need data from the server like intro I want to render it immediately. so for all similar components in this page.
for example intro render right way, the foo will render when it enter to the viewport and display a loader and when the data is resolved it change to the data.
I want to see the page ASAP. so each component have its own loader.
Here I become with some problems:
One: I need to know if the product exist. if not it need to be redirect to 404 page. so where to put this logic? each component or the parent component? I think the parent component, but when it take 2 min to load the data I'll get a blank screen seince the components are not ready and not be render. which is conflict with "Important notes".
Two: when the productId is change (navigate to another product) the foo and bar need to resolve the data, so in those two components I need to listen to the route change (which makes duplication in my code) (and slow performance?) and still I need to check if the productId is exist or not.
in this example the items don't change because it need to trigger the useProduct function.
setup() {
const { route, router } = useRouter();
const productIdToLoad = computed(() => route.value.params.productId);
const { items } = useProduct({ productId: productIdToLoad });
return { items }
}
and if I do it in watch I lose the reference
setup() {
const { route, router } = useRouter();
const items = ref([]);
const productIdToLoad = computed(() => route.value.params.productId);
watch(productIdToLoad, (v) => {
items = useProduct({ productId: v });
});
return { items }
}
I am writing an angular application. in which I am managing state using redux.
I have a store like below
export interface State {
data {
items: any[];
}
}
I have a return selector for getting Items like below
export const getItems = createSelector(getItemState, fromItem.getItems);
fromItem.getItems is like below =>
export const getItems = (state: State): any[] => state.items;
and in my component I have subscribe for selector of items like below
this.store.select(getItems).subscribe((items) => {
this.localItems = items;
}
everything is working fine but in getItems subscription I am getting the reference to the items which are stored in the store. And, if I update any local item it also gets reflected into the store.
I was expecting the subscription of selector (getItems) to return a cloned copy of items from the store but it is returning the reference.
Am I doing anything wrong or is there any way to get a cloned copy of items from the store?
What you're describing is the correct behavior.
State mutations should only happen in reducers in a pure way.
Doing it this way makes using a store performant, we can simply check if the reference is the same - this is very cheap.
I use getState to get a clientId that I need to include in every api call right now. Problem is that this interrupts data flow as the app doesn't rerender when clientId changes. Do I have to manually get the clientId in every component that I need to include it in or is there a better alternative? (clientId is also in store and is fetched first when the user logs in)
Sounds like a good candidate for the use of Context.
Here's a fictitious example of how you can set the client ID at a high level but reference it in nested components without having to query the Redux store each time using Hooks:
App
const ClientContext = React.createContext(null);
function App(props) {
return (
<ClientContext.Provider value={props.clientId}>
<MyApiComponent />
</ClientContext>
)
}
const mapStateToProps = getState => ({
clientId: getState().clientId
})
export default connect(mapStateToProps, {})(App);
So we only need to connect the App to the store to retrieve the client ID, then using Context we can make this value accessible to nested components. We can make use of useContext to pull that value in to each component
function MyApiComponent() {
const clientId = useContext(ClientContext);
...
return <MyNestedApiComponent />;
}
function MyNestedApiComponent() {
const clientId = useContext(ClientContext);
...
}
Whether it's function or class components you are using, the principle is the same - Context is used to share global state down to nested components.
So let's say I have this global JS function file that other components use to make rest calls, if the response is unauthorized I want it to change the state of a React component to loggedIn:false. Is this possible?
Looks like a use case of redux. You will maintain loggedIn in your store and connect whichever component requires this info with the store.
Else there are two other ways not that good which I will call hacks.
1) Maintain this in url query params and read the params in component.
2) Maintain this in sessionStorage or localStorage.
3) Maintain it in window.isLoggedIn
But since this is login related info I would avoid using these ways. For some other global, you can use above mentioned ways.
Take a look at redux here
https://redux.js.org/basics/usagewithreact
class SomeComponent extends React.Component {
...
async getData() {
await response = fnToGetData();
if (response.unauthorized) {
this.props.setAuthorizationStatus(false);
// or if you want to set authorization only in this component
// this.setState(() => ({authorized: false}));
} else {
// do sth with the data
}
}
}
Where setAuthorizationStatus lives somewhere on top of your app and is passed down through props (you can also use context to pass it down conveniently).