I want my components to re-render everytime I call 'state.set(...)', even if the values doesn't change.
So hey guys, i have this reducer, which is called everytime screen is resized:
import Immutable from 'immutable';
const initialState = Immutable.fromJS({
width: ''
});
export default (state=initialState, action) => {
switch(action.type){
case "SCREEN_RESIZE":
if(action.payload >= 768){
return state.set('width', 'big');
}
else{
return state.set('width', 'small');
}
default:
break;
}
return state;
}
I'm using ImmutableJS along with redux, so my store is a map (entire store) of maps (each reducer).
The problem is that my components only re-renders when we change 'width' from 'big' to 'small', or from 'small' to 'big', that is, when value changes!
I want it to re-render even when I set width from 'big' to 'big' or from 'small' to 'small'.
Am I making any mistake?
This is my rootReducer
import { combineReducers } from 'redux-immutable';
import reducer1 from './reducer1_reducer';
import reducer2 from './reducer2_reducer';
import reducer3 from './reducer3_reducer';
import screenSize from './screenSize_reducer';
import reducer5 from './reducer5_reducer';
import rounting from './routerReducer';
const rootReducer = combineReducers({
reducer1,
reducer2,
reducer3,
screenSize,
reducer5,
routing
});
export default rootReducer;
If you want to re-render on each screen-resizing, you're probably going to want to make the props of the component have the actual screen dimensions, like so:
<MyRerenderableComp width={this.props.screenWidth} height={this.props.screenHeight} />
You're question is somewhat similar to this post: Reactjs - Rerender on browser resize
Hope that helps?
Related
const Component = () => {
const [newName, setnewName] = useState('');
const updateName = (max: number) => {
//logic to update newName
};
return (
<>
<div>{newName}</div>
</>
);
};
export default Component;
When ever the newName variable's value changes I want to add some effect in the ui for it. Is there any way that this can be done?
Yes. You can use the useEffect hook to achieve this, and add the newName state as a dependency.
For example, take a look at the following. I will demonstrate through console.log("hey, newName changed") every time the variable state changes.
const Component = () => {
const [newName, setnewName] = useState('');
useEffect(() => {console.log("hey, newName changed!"}, [newName])
const updateName = (max: number) => {
};
return (
<>
<div>{newName}</div>
</>
);
};
export default Component;
Import it with useState.
Now, you may ask "yes, but youre only consoling something out, not actually doing anything with the CSS transition". Rest assured, you can take a similar approach.
The useEffect hook is simply a function that watches for state change. From the callback function, just add your custom css transition class, or fire a function that changes the CSS.
As I am not sure what kind of transition effect you want as you did not specify it in your question, so forgive me for not being able to provide a specific example. I hope this helps you.
use useEffect and dependancy in to change state and using that state you can update class, and then write aniamtion css for that class , hope this will help...
import React from "react";
import "./App.css";
function App() {
const [newName, setnewName] = React.useState('Lorem');
const [transition, setTransition] = React.useState(false)
React.useEffect(()=>{
setnewName('ipsum')
setTransition(true)
},[newName])
return (
<>
<h1 classNane={`${transition?'animate':''}`} >{newName}</h1>
</>
);
}
export default App;
Should i use Router.back for default function value in my prop?
Hi, I'm working with Next.js and came across the following problem
I have a component with optional prop onPageBack and wondering if using Router.back as default value for it instead of the hook one is the right choice
import Router from 'next/router';
const MessagePage = ({ onPageBack = Router.back }) => {
return (
<button onClick={onPageBack}>Back</button>
);
};
vs
import { useRouter } from 'next/router';
const MessagePage = ({ onPageBack }) => {
const router = useRouter();
const handlePageBack = onPageBack || router.back;
return (
<button onClick={handlePageBack}>Back</button>
);
};
The first one looks more JS native, but I wonder if using global Router object here, which is not mentioned in the Next.js documentation, is the right choice, as well as I'm not sure how good it's going to do with other native stuff Next.js does with routing under the hood
I should say that this prop is required, as onPageBack has a bit different behavior depends on where the component's used
Hiii i have one array like more than one object and when store data from redux i need to remove automatic from array after 5 second.
welcome to the community! For your problem maybe use a useEffect hook in the app component, eg:
import foo from "foo.js";
import blahblahblah from "xxx.js";
import React from "react";
import {useDispatch} from "react-redux";
// ..;
function App(){
const dispatch = useDispatch();
React.useEffect(()=>{
while(true){
setTimeout(()=>{
dispatch.runSomthing(myAmazingData);
},5000);
}
}, []);
return(
<div>
<p>Welcome to my amazing website😀</p>
</div>)
}
export default App;
Next time, show some code! And explain your intentions and what you want to do.
Thanks!
I have created a bare-bones Meteor app, using React. It uses the three files shown below (and no others) in a folder called client. In the Console, the App prints out:
withTracker
rendering
withTracker
rendering
props {} {}
state null null
In other words, the App component is rendered twice. The last two lines of output indicate that neither this.props nor this.state changed between renders.
index.html
<body>
<div id="react-target"></div>
</body>
main.jsx
import React from 'react'
import { render } from 'react-dom'
import App from './App.jsx'
Meteor.startup(() => {
render(<App/>, document.getElementById('react-target'));
})
App.jsx
import React from 'react'
import { withTracker } from 'meteor/react-meteor-data'
class App extends React.Component {
render() {
console.log("rendering")
return "Rendered"
}
componentDidUpdate(prevProps, prevState) {
console.log("props", prevProps, this.props)
console.log("state", prevState, this.state)
}
}
export default withTracker(() => {
console.log("withTracker")
})(App)
If I change App.jsx to the following (removing the withTracker wrapper), then the App prints only rendering to the Console, and it only does this once.
import React from 'react'
import { withTracker } from 'meteor/react-meteor-data'
export default class App extends React.Component {
render() {
console.log("rendering")
return "Rendered"
}
componentDidUpdate(prevProps, prevState) {
console.log(prevProps, this.props)
console.log(prevState, this.state)
}
}
What is withTracker doing that triggers this second render? Since I cannot prevent it from occurring, can I be sure that any component that uses withTracker will always render twice?
Context: In my real project, I use withTracker to read data from a MongoDB collection, but I want my component to reveal that data only after a props change triggers the component to rerender. I thought that it would be enough to set a flag after the first render, but it seems that I need to do something more complex.
This a "feature", and it's not restricted to Meteor. It's a feature of asynchronous javascript. Data coming from the database arrives after a delay, no matter how quick your server is.
Your page will render immediately, and then again when the data arrives. Your code needs to allow for that.
One way to achieve this is to use an intermediate component (which can display "Loading" until the data arrives). Let's say that you have a component called List, which is going to display your data from a mongo collection called MyThings
const Loading = (props) => {
if (props.loading) return <div>Loading...</div>
return <List {...props}></List>
}
export default withTracker((props) => {
const subsHandle = Meteor.subscribe('all.myThings')
return {
items: MyThings.find({}).fetch(),
loading: !subsHandle.ready(),
}
})(Loading)
It also means that your List component will only ever be rendered with data, so it can use the props for the initial state, and you can set the PropTypes to be isRequired
I hope that helps
Unsure if you're running into the same error I discovered, or if this is just standard React behavior that you're coming into here as suggested by other answers, but:
When running an older (0.2.x) version of react-meteor-data on the 2.0 Meteor, I was seeing two sets of distinct renders, one of which was missing crucial props and causing issues with server publications due to the missing data. Consider the following:
// ./main.js
const withSomethingCount = (C) => (props) => <C { ...props } count={ ... } />
const withPagination = (C) => (props) => <C { ...props } pagination={ ... } />
const withSomething = withTracker((props) => {
console.log('withSomething:', props);
});
// Assume we're rending a "Hello, World" component here.
export const SomeComponent = withSomethingCount(withPagination(withSomething(...)));
// Console
withSomething: { count: 0 }
withSomething: { count: 0, pagination: { ... } }
withSomething: { count: 0 }
withSomething: { count: 0, pagination: { ... } }
For whatever reason, I was seeing not only N render calls but I was seeing N render calls that were missing properties in a duplicate manner. For those reading this and wonder, there was one and only one use of the component, one and only one use of the withTracker HoC, the parent HoCs had no logic that would cause conditional passing of props.
Unfortunately, I have not discovered a root-cause of the bug. However, creating a fresh Meteor application and moving the code over was the only solution which removed the bug. An in-place update of the Meteor application (2.0 to 2.1) and dependencies DID NOT solve the issue... however a fresh installation and running a git mv client imports server did solve my problems.
I've regrettably had to chalk this up to some form of drift due to subsequent Meteor updates over the two years of development.
referring from the link.
https://react-redux.js.org/next/api/hooks#performance
what i understand the benefit of useSelector hook, is to avoid wrapper hell. Wrapper hell is happening due to the usage of connect HOC. If we have to use React.memo HOC with useSelector due to perfomance reason, would it be better approach to simply use connect HOC instead? Because in any case we would have to be in hell of wrappers. If the hell is not by connect then would be by React.memo.
Any one please explain the benefit of React.memo over connect.
Well, first, interesting enough although React.memo is a HOC it does not create the same nesting as connect does. I have created a test code:
import React from "react";
import ReactDOM from "react-dom";
import {connect, Provider} from 'react-redux'
import { createStore } from 'redux'
import "./styles.css";
const MemoComponent = React.memo(function MyMemo() {
return <div>Memo</div>;
});
const ConnectedComponent = connect(null,null)(function MyConnected() {
return <div>ReduxConnectComponent</div>;
})
const store = createStore(()=>{},{})
function App() {
return (
<Provider store={store}>
<MemoComponent />
<ConnectedComponent/>
</Provider>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
And here is the structure rendered:
We can see that a content for connect is rendered deeper.
Second, the docs say:
by default useSelector() will do a reference equality comparison of the selected value when running the selector function after an action is dispatched, and will only cause the component to re-render if the selected value changed. However, unlike connect(), useSelector() does not prevent the component from re-rendering due to its parent re-rendering, even if the component's props did not change.
that means the component which useSelector will not be re-rendered when unrelated parts of the store change. And this is the most important part of the optimization. Whether optimizing with React.memo or not is now completely depends on your decision and in most cases, it simply is not needed. We use React.memo only in cases when the component is very expensive to render.
To summarize, connect wrapper was required to connect to the store. With useSelector we do not have to wrap anymore. We still need to wrap with React.memo in rare cases when we need to optimize some heavy components. The work of React.memo was also done by connect but in most cases, it was premature optimization.
I have been trying to get an answer for quite some time but the answers I got weren't clear. Although the theory in the Redux documentation isn't complicated: useSelector uses strict equality === and connect uses shallow equality to determine. So in both cases, if you are "pulling" a primitive value from your Redux state (number, string, boolean) you will be having the same outcome. If values haven't changed none of the components will rerender. If you are "pulling" non-primitives (arrays or objects) and the values haven't changed for both cases (useSelector, connect), then the component that uses useSelector will still rerender as of course [] === [] will always be false, as they are referencing different arrays, where as the connected component will NOT rerender. Now in order to make useSelector behave similarly and not rerender, you can do this:
const object = useSelector(state => state.object, shallowEqual) You can import shallowEqual from react-redux. Or alternatively use a memoized version of that piece of state by using the reselect library:
const makeGetObject = () => createSelector(state => state.object, object => object)
and add it to your selector such as: const object = useSelector(state => state.object, makeGetObject); I have created this codesandbox when I was trying to get at the bottom of it (check the comments at the WithUseSelector component): useSelector vs connect()
I just customized useSelector hook to avoid that and it works nice
import { useSelector, useDispatch } from 'react-redux'
import { _lodash } from '../../../lodash'
export const useCloneSelector = (selector = (obj) => obj) => {
const selectWithClonedState = (state = {}, ...others) => selector(_lodash.cloneDeep(state), ...others)
return useSelector(selectWithClonedState, _lodash.isEqual)
}
export { useDispatch, useSelector }