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).
Related
I am using react redux saga to implement something in a calendar application. This calendar application has multiple settings/params. One of them is the currentAccountId, which is in the initalState of a redux file and I want to render it dynamically.
const initialState = {
currentAccountId: ''
};
However, in order to do this, I need access to the state object on a different redux saga file. How do I access this? Because when I try to do something along the lines of const state = yield select(); outside of a generator function to access state, it tells me something like not accessible outside of a generator function. Is there some way I can access state?
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.
I am using javascript async await to make a service call to the server, mostly from componentDidMount or componentDidUpdate, but when I want to send the response as props to other components, I am currently updating the state of the component with the response. But since as the user I dont actually modify that particular state, it kinda feels like a wasted variable. Is there any way to get it as props to my component instead of setting the state.
class Example extends React.Component {
constructor(props){
super(props);
this.state = {data: {}}
}
componentDidMount(){
const {data} = await getService();
this.setState({data})
}
render(){
return (<ChildComponent data/>)
}
}
Is it possible to get the data which is a property from response as props instead of setting it as state and retrieving it from state
Assuming your example is a scaled down version of your actual app, I would say what you are doing is fine. Otherwise, I would have a minor query around why not have ChildComponent do they fetching for data to avoid 'prop drilling' i.e. passing props through multiple layers of components to eventually reach a component that cares about the data.
It's not fine to make an async call in componentDidMountbecause whenever the state is changed, the componentDidMount is called ==> there is a lot of call to the service.
there is a more elegant way to do it, using Redux(state management tool which contains the state of the application), by doing #async(make here all your call services and automatically are connected to other component without passing it in props)
My understanding of state variables in React is that only data that changes as a result of user interaction or asynchronous data flow should be stored in state. What if I need to request list data from several APIs and then combine these to make a new master list to serve as a constant source of truth that may need to be used by various component methods during phases of user interaction? What is the correct place to store unchanging data like this? It's tempting to put this data in state for easy access but that doesn't seem right. Thanks.
You don't need to use redux, in this case. It's OK to save your API data call to state, even though the data won't change. If you don't want to save it to state you can save it to a static or global variable.
class App extends React.Component {
API_DATA = []; // save data here
state = {
api_data: [] // it's ok too
}
componentDidMount = () => {
// call to api
// save data to API_DATA
this.API_DATA = data;
}
}
This is where something like React hooks or Redux would come in handy. If you're unfamiliar, both can be used to globally store state. Redux would be better for high frequency changes but it sounds like hooks would be best for your situation.
There are plenty of tutorials out there for this on Youtube, the React subreddit, etc.
In my project I have a call to an action that makes a webservice call and in turn dispatch actions to the result of the ws, these actions edit the store.
My problem is in :
ComponentDidUpdate () {
If (this.props.messages.length) {
Const items = this.props.messages.filter (this.isDisplayable);
This.timer = setInterval (() => {
If (items.length> 0) {
This.props.popItem (items);
} Else {
ClearInterval (this.timer);
}
}, This.props.interval);
}
}
In fact it is launched several times and I have warnings of
Warning: flattenChildren (...): Encountered two children with the same
key, 1. Child keys must be unique; When two children share a key,
only the first child will be used.
I used the componentDidMount but it launches it before api responds.
my question is:
Is that there is a way to update the component only at the response of my action, or alternatively to pass the warnings ?
try this :
componentWillReceiveProps(nextProps) {
if (this.props.messages === nextProps.messages) return;
i had some probleme and i resolve it by force update
forceUpdate () {
If (this.props.messages.length) {
...
}
}
In my project I have a call to an action that makes a webservice call and in turn dispatch actions to the result of the ws, these actions edit the store.
None of the methods componentDidMount and componentDidUpdate are good.
Observe the Store in Redux and update your component accordingly when the correct action TYPE is found.
Since you are using the Redux architecture, the state for all your components is in a single place — in the Store.
yes i know, but the problem is that componentDidUpdate is called several times which gives me the index error.
This is quite normal in React. Check this lifecycle.
What you should do is the govern the Redux architecture.
I will try today to provide some diagrams for you.
In general, anything you do will be from the global Store.
You may forget the React.Component state, and props you had in the non-Redux applications.
You typically need to use the Wrapper as a context provider around your app, where the context is the property of React.Component.
The context will be passed to all children and grandchildren so this will be the global Store organization.
Then you will need to read the Store from the context, and call the two typical methods: dispatch and subscribe.