Is there a way to update the Redux store before the ReactDOM.render(...) is runned?
Something like store.dispatch(...).then(() => ReactDOM.render(...))
Or a way to just replace the entire "state" of the store?
I am making an API with React components that is used inside another application with another framework, Dojo. Because of this we are using ReactDOM.render(...) and ReactDOM.unmountCompoentAtNode(...) when the component should appear/disappear.
So in the API, I am reusing the redux store, since it is not deleted from the memory/RAM even though a React component is unmounted via ReactDOM.unmountComponentAtNode(...). If I did not reuse the store, but made a new one every time the React component should render, the actions where "fetched by the Redux store" more and more times. Because of this I would like to ensure that I get to refresh the Redux store before I mount the component again.
Given that the rendered state should depend on the redux store, have you seen redux-thunk ?
One way is to have a show a spinner when the API endpoint is being reached out to.
After setting the state from the API response, go ahead and show the real component.
You are approaching the solution in the wrong way. For this use case, we have life cycle methods in components
ReactDOM.render(<App />, document.getElementById('root'))
In this code I am rendering App component, to solve your problem I'll use componentDidMount life cycle method of App and from there I'll dispatch the API call.
class App {
componentDidMount() {
dispatch(MY_ACTION)
}
render() {
return (<h1>dummy</h1>)
}
}
For hooks based functional component, you need to use useEfect
const App = () => {
useEffect(() => {
dispatch(MY_ACTION)
}, [])
return (<h1>dummy</h1>)
}
Related
I was learning React and created two class components having respective states. Then, I learned about Redux and decided to transfer states into redux store. The question is "Is it best practice to change class componenents into functional components since we get state via props from redux store?"
Functional components with react hooks is the new standard of coding on React. For store management(f.e. redux) you may use as classes as functional components, but most of the libs moved to functional components and you may not use all benefits of last versions of them.
Why I prefer functional components and hooks over classes:
Cleaner render tree. No wrapper components
More flexible code. You
can use useEffect on different state changes, in classes you have
only componentDidUpdate for ANY state/props change
You can define your custom hooks to keep your code clean and shiny
IMHO, yes, I suggest that you should switch from class-based component to functional component as soon as possible.You might not want to know how the class-based components have bugged me so hurt before I decided to go with Hooks. The number of components in my large project is now over 400 (including both smart and dumb components) and keep increasing. Hooks keep my life easier to continue developing and maintaining.
Have a look at this useful article: https://blog.bitsrc.io/why-we-switched-to-react-hooks-48798c42c7f
Basically, this is how we manage state with class-based:
It can be simplified to half the lines of code, achieving the same results with functional component and useState, useEffect:
Please also take a look at this super useful site: https://usehooks.com/
There are many useful custom hooks from the community that you can utilize. Below are the ones that I have been using all the time:
useRouter: Make your life easier with react-router. For example:
import { useRouter } from "./myCustomHooks";
const ShowMeTheLocation = () => {
const router = useRouter();
return <div>Show me my param: {router.match.params.myDesiredParam}</div>;
}
useEventListener: simplify your event handler without using componentDidMount and componentWillUnmount to subscribe/unsubscribe. For example, I have a button that needs to bind a keypress event:
import { useEventListener } from "./myCustomHooks";
const FunctionButton = () => {
const keydownHandler = event => { // handle some keydown actions };
const keyupHandler = event => { // handle some keyup actions };
// just simple like this
useEventListener("keydown", keydownHandler);
useEventListener("keyup", keyupHandler);
}
useAuth: authenticate your user.
import { useAuth } from "./use-auth.js";
const Navbar = (props) => {
// Get auth state and re-render anytime it changes
const auth = useAuth();
// if user is authenticated, then show user email, else show Login
return <div>{auth.user? auth.user.email: "Login"}</div>;
}
useRequireAuth: handle redirect your user if they are signed out and trying to view a page that should require them to be authenticated. This is composed by useRouter and useAuth above.
import { useRequireAuth } from "./myCustomHooks";
// Dashboard is a page that need authentication to view
const Dashboard = () => {
const isAuth = useRequireAuth();
// If isAuth is null (still fetching data)
// or false (logged out, above hook will redirect)
// then show loading indicator.
if (isAuth) {
return <div>Fetching data, please wait!</div>
}
// {...{ isAuth }} is similar to:
// isAuth={isAuth}
return <Dashboard {...{ isAuth }} />
}
Hope this helps!
First of All, States can be used only in Class Component. In React's latest version there's a huge update that allows functional components to declare and use state using React-Hooks. So, the best practice I would personally suggest you is to use Class Component when you use the Redux Store. As you're a beginner, Please use a functional component where you don't use any state or props and just render DOM elements (Note: Functional components can accept props). Once you learn the differences properly, go with React-Hooks.
I hope it helps!! Happy Coding!!
i've been developing an app using react 16.8 and to avoid importing Axios in every component i started making use of the context API to hold data from all my requests on its internal state and reference this data in the component where i need it with the <Consumer/>, but the number of properties in the state grew considerably, i wonder if this is ok, and if it is should i clean the state after using the data where i needed, in a method like ComponentWillUnmount?
Class ContextProvider {
state = {
prop1: [],
prop2: [],
prop3: [],
{...n}
}
getProp1Data = () => {
Axios.get(url)
.then(res => this.setState({prop1: res.data})
}
{.... n}
}
You should consider using Redux since with Redux you can travel between the state history in development, and re-evaluate the current state from the action history when the code changes. In this way you be able to import Axios only once to your middle ware and to make your code more clear.
In case you consider to use ComponentWillUnmount you won't be 'cleaning' your state since setState() can't be called on this life cycle method. ComponentWillUnmount is related to the competent itself on the DOM and not to the state. There's not a problem with your props being 'grew considerably' and you may use as many as you like.
React newbie here: I have noticed that the component state gets cleared on unmount. is there a way to prevent it? is it using redux?
As you say, when a component is unmount you can not access to the state. And thats the way it is because the lifecicle of the component.
What you can do is try to save the state of the component that was instantiated while it is mounted and every time it is updated.
You can use the storage and use simple javascript.
You can have the state in the parent or another ancester instance.
You can have the state in the redux store. Note that your component will receive the vars as props, so it wont be the state properly said.
You can use redux in order to manage the state and the states values through time. I recommend you the redux-devtools-extension and also this article about it.
You have a plethora of options. You can either use a state management tool, like redux, context API and so on, or you can pass-in a callback to your parent component and trigger it on childComponentWillUnmount like this:
ParentComponent.jsx:
childComponentWillUnmount = (data) => {
console.log('my data', data);
}
render(){
return <div>
<Child componentUnmountCallback={this.childComponentWillUnmount()}/>
<div>
}
<div>
Child.jsx
...
componentWillUnmount() {
this.props.childComponentWillUnmount(this.state);
}
...
I am new to React and trying to implement an application. Basically
my application have several routes. Each
route is backed by the same set of back end data +some api calls
specific to route taking back end data attributes as api params.
So I wrote a Higher order component to call the
API to retrieve the back end data,store the state in redux store and
pass it as props to the wrapped component which works fine.
const withData = (WrappedComponent) => {
class DataWrapper extends Component {
constructor() {
this.state = {
c: {},
d: []
};
}
componentDidMount(){
this.props.fetchData();
}
componentWillReceiveProps(nextProps){
this.setState({
c: nextProps.data.CSubset,
d: nextProps.data.DSubset
});
}
render() {
return <WrappedComponent {...this.props} {...this.state}/>;
}
const mapStateToProps=(state)=>({
data:state.appData
});
return connect(mapStateToProps,{fetchData})(DataWrapper);
}
export default withData;
class AppComponent extends Component{
componentDidMount(){
this.props.fetchComponentSpecificData(c.dataAttribute);
}
render(){
return <div />;
}
}
export default connect(null,{fetchComponentSpecificData}(withData(AppComponent);
But the issue is API gets called for all routes.It should be one
time per full application flow.
The component specific data fetch happens before the common back end data is available causing the component specific API call to fail.
User can type in the URL and launch
into any route within application and the API has to be called only
once and the HOC has to systematically route to the correct route
based on data.
Please advise on the design approach
I would say that the most "Reacty" way of doing this would be to implement the global API calls in the componentWillMount method of the top-level component (say, AppComponent). Right now, you have put it in a component that will be mounted for each subcomponent of your app, and it might be tricky to prevent the API call from being fired every time it mounts.
Using a HOC to provide those data to other components of your app is not a bad idea, but it makes your app a bit more implicit, and I don't think you're gaining a lot : you're adding a component with implicit behaviour instead of just adding a line in mapStateToProps.
Firing page-specific API calls after the global API call has succeeded is quite tricky. You're going to need a way to monitor the fact that the global API call has resolved, and in React/Redux way of thinking, this means dispatching an action. To dispatch actions asynchronously, you're going to need a Redux middleware such as redux-thunk or redux-saga (I believe redux-thunk is a lot easier for beginners). Now, if you have a way to know whether or not the global API call is a success, you can wait for a specific action to be dispatched (say, GLOBAL_API_CALL_SUCCESS). Now, this is the part where I'm doing myself a bit of publicity : I've written redux-waitfor-middleware that allows you to wait for a specific action to be dispatched. If you used it, it might look like this :
export async function fetchComponentSpecificData() {
await waitForMiddleware.waitFor([GLOBAL_API_CALL_SUCCESS]);
// perform actual API call for this specific component here
}
I'm not saying that waitFor middleware is the best tool to achieve this, but it's probably the easiest to understand if you're beginning!
trying to understand React-Redux, i find it unusual that all my components get new props when ever any slice of the state get changed. so is this by design or i'm doing something wrong ?
example App
class App extends React.Component {
render(){return (
<div>
<Navbar data={this.props.navbar} />
<Content data={this.props.content} />
</div>);
}
}
select (state) => ({ navbar:state.navbar, content:state.content});
export default connect(select)(App);
Components
export const NavbarForm = props => {
console.log('RENDERING with props--->',props);
return (<h1>NAV {props.data.val}</h1>);
};
export const ContentForm = props => {
console.log('RENDERING CONTENT with props--->',props);
return (<h1>CONTENT {props.data.val}</h1>);
};
////////INDEX.js//////
const placeholderReducer = (state={val:0},action)=>{
//will update val to current time if action start with test/;
if(action.type.indexOf('TEST/') === 0)return {val:Date.now();}
return state;
}
export const rootReducer = combineReducers({
navbar:placeholderReducer,
content: (state,action)=>(state || {}), //**this will never do a thing.. so content should never updates right !!**
});
const store = createStore(rootReducer, {}, applyMiddleware(thunk));
render( <Provider store={store}> <App /></Provider>, document.getElementById('app')
);
setInterval(()=>{ store.dispatch(()=>{type:'TEST/BOOM'}) },3000);
okay in this app, what i expect is that Navbar component will get updated every 3000ms while content component will never updates because its reducer will always return the same state.
yet i find it really strange that both components does reRender every time an action is fired.
is this by design ? should i worry about performance if my app has 100+ component ?
This is entirely by design. React assumes that your entire app will be re-rendered from the top down by default, or at least a given subtree will be re-rendered if a certain component does a setState or something similar.
Because you only have the very top component in your app connected, everything from there on down is React's standard behavior. A parent component re-renders, causing all of its children to re-render, causing all of their children to re-render, and so on down.
The core approach to improving UI performance in React is to use the shouldComponentUpdate lifecycle method to check incoming props and return false if the component does not need to re-render. This will cause React to skip re-rendering that component and all of its descendants. Comparisons in shouldComponentUpdate are generally done using shallow reference equality, which is where the "same object references means don't update" thing becomes useful.
When using Redux and connect, you will almost always find yourself using connect on many different components in your UI. This provides a number of benefits. Components can individually extract the pieces of the store state that they need, rather than having to hand them all down from the root component. In addition, connect implements a default shouldComponentUpdate for you, and does a similar check on the values you return from your mapStateToProps function. So, in a sense, using connect on multiple components tends to give you a "free win" in regards to performance.
Further reading on the topic:
Redux FAQ: Connecting multiple components
React/Redux Links: Performance articles
Yes this is by design. Action is dispatched. Reducers run. Store subscribers get notified "the store has changed". Connected components are store subscribers.
Typically you just don't worry about it until you can actually measure a performance problem that you can attribute to this - don't prematurely optimize.
If you find out that it is a problem, then you can do one of the following:
Add a shouldComponentUpdate method to your components so they can see that the props they received aren't different and do not need to render (there are lots of Pure Render mixins & high order components available to make this easy)
Instead of connecting the top-level app, connect the Navbar and Content components directly. The App will never rerender, but the children will if the store changes. And react-redux automatically uses shouldComponentUpdate to only re-render the connected components that actually have new props.