// import { useState } from 'react'
import Res from './responsiveMenu/Res'
import NormalWidth from './navNormalwidth/NormalWidth'
const Navbar=()=>{
const [click,setClick]=useState(true)
// function to change from true to false
const navBtn=()=>{setClick(!click)}
const screenwidth=window.innerWidth
return(
<>
{screenwidth<'640' ? <Res btnF={navBtn} click={click}/>:screenwidth>'640'?<NormalWidth/>:''}
</>
)
}
export default Navbar
why when the screen is 640 is works but when i make it bigger i the menu btn stays until i press it then it will render the normal component
Please use the viewport unit with width.
eg:
width:100vw;
As mentioned in the comments, your component does NOT rerender when the window size is changing. You need to register a listener, which updates the a react state which causes your component to rerender.
State of the art would be to create this via a hook. As this is a very common functionality people already implemented examples of such a hook for you.
You can find a good one here. Not library needed.
https://usehooks.com/useWindowSize/
If you are not yet familiar with using hooks, the official React documentation is very good.
https://reactjs.org/docs/hooks-intro.html
Related
In my Reactjs project I have a component that contains a Modal that has its own states and when 1 (or more) of these states change, they trigger a re-render of that component:
import React from "react";
import CustomModalComponent from "./CustomModalComponent";
const MainComponent = () => {
const [isModalOpen,setIsModalOpen] = React.useState(false);
console.log("main component");
return(
<React.Fragment>
<section>Some UI here that can also turn modal state to true</section>
<CustomModalComponent open={isModalOpen} toggleOpen={() => setIsModalOpen(!isModalOpen)} />
</React.Fragment>
);
}
export default MainComponent;
As I said whenever a state changes inside that custom modal component, it triggers a re-render in my main component which is due to the fact that I have a state that changes, but I was wondering if there is a way to change this "behavior" since if my main component is a big one, re-renders will take away from the performance.
You don't need to worry about rerenders until they are a problem. It is a common beginner's error to optimize for reducing rerenders. Sadly, a lot of false material exists online around this that suggests you need to be thinking about this from day 1. Rerenders are usually extremely cheap and simply don't matter.
Keep in mind a "rerender" doesn't mean it loads all the HTML up again in the DOM. Internally React diffs over the state, meaning it only makes small edits when the state changes.
I've got a sample Resium project that shows the map. I've added a simple onClick that sets some state which is NOT being used anywhere - I just set it. Still, it causes the entire map to redraw & flicker UNLESS I remove the terrainProvider. Example (terrainProvider is commented out) if you move/click the mouse, the entire Cesium UI flickers and redraws everything. I'm using React 17, Resium 1.14.3 (Cesium 1.86.1). Any idea what's going on?
import React, { useState } from "react";
import { Cartesian3, Color } from "cesium";
import { Viewer, Entity } from "resium";
import * as Cesium from 'cesium';
export default function App() {
const [currentPos, setCurrentPos] = useState(null);
const handleMouseClick = (e, t) => {
setCurrentPos("xxx");
}
return (
<Viewer full
onClick={handleMouseClick}
onMouseMove={handleMouseClick}
// terrainProvider={new Cesium.CesiumTerrainProvider({ url: 'https://api.maptiler.com/tiles/terrain-quantized-mesh-v2/?key=xxxxxxx' })}
>
<Entity
name="Tokyo"
position={Cartesian3.fromDegrees(139.767052, 35.681167, 100)}
point={{ pixelSize: 10, color: Color.RED }}
/>
</Viewer>
);
}
My guess is this. No matters that the currentPos is not used in the component, is still part of the component's state, then the components re-renders.
In every render, the terrainProvider prop is receiving a new instance, so this causes that the entire Viewer re-renders too.
Maybe you can save your instance as state in the component and don't create a new one everytime that the component is re-render.
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 have been using React and D3 separately and now have a project where I need low level control over the plotting function of an application. Basically, I need to be able to go and fetch higher resolution data from a database as the user zooms in, and vice versa as the user zooms out, on a plot.
I have found a few methods to use D3 and React together. I wanted to try and keep all of my React code based around the hooks API as that is what is used for the rest of the code base. I am struggling to get the hooks equivalent for the specific cases that I am facing. The documentation on React hooks is great but I think my situation is more of an edge case and I have not seen any discussion relating to similar use cases to what I have.
The logic of the code is fairly straight forward:
I have a main container, call it App.js, that hold some state. App.js renders a Wrapper component (which is where the challenge is occurring) and then the Wrapper.js file simply creates the D3 Plot. The D3 plot is just typical D3 code for a line plot with some zoom events.
The Wrapper code:
import React, { Component } from 'react';
import Plot from './Plot'; // D3 plot
class Wrapper extends Component {
// Sets up plot when Wrapper first added to DOM tree
componentDidMount(){
this.setState({
plot: new Plot(this.refs.plot, this.props.data, this.props.updateData)
});
};
// Do not allow React to re-render the Wrapper and therefore the Plot
shouldComponentUpdate(){
return false;
};
// When the data prop changes, execute the update() method in the plot file
componentWillReceiveProps(nextProps){
this.state.plot.update(nextProps.data) // the .update() method calls props.updateData()
}
render(){
return <div ref="plot"></div>
}
}
export default Wrapper;
I have started putting together the hooks version below but I cannot come up with suitable emthods that meet the specific requirements of what I am after for the cases of the shouldComponentUpdate and componentWIllReceiveProps blocks.
hooks version:
import React, { useEffect, useRef } from 'react';
import Plot from './Plot'; // D3 plot
const Wrapper = props => {
// destruct props
const {
data = props.data,
fields = props.fields,
click = props.click
} = props
// initialise empty ref
const plotRef= useRef(null);
// ComponentDidMount translated to hooks
useEffect(() => {
new Plot(plotRef, data, updateData)
},[]) // empty array ensures the plot object is only created once on initial mounting
// shouldComponentUpdate
useEffect(...) // This won't work because render has already occurred before useEffect dependency array diffed?
// ComponentWIllReceiveProps
useEffect(() => {
plot.update(data)
}, [data]) // This won't work because component needs to have re-rendered
return (
<div ref= {plotRef}></div>
)
};
export default Wrapper;
What I am trying to achieve is blocking any rendering of the D3 chart after the initial mount, but then if the data props changes in the parent component, execute a method in the D3 class without allowing React to re-render the Wrapper component.
Is this at all possible or am I better off leaving this as a class based component?
I have been banging my head against a wall trying to get the logic without any success so any input would be greatly appreciated.
you can wrap your return value in React useMemo with suitable dependencies.
https://reactjs.org/docs/hooks-reference.html#usememo
This is my component. It renders the first time. Subsequently, even though render gets called, it does not change the DOM.
Render is getting called at the right times, because I have redux set up and my 'mapStateToProps' seems to work correctly, in that it detects a change in application state, and calls render().
The console log does log the fact that the string has changed.
You would probably like to see more code, but I'm hoping that I'm missing a fundamental concept here that someone can just point out. I'm not sure how to put my whole project up here. Thanks. Again, render DOES get called, so shouldn't it update the DOM?
import React from 'react';
import { Component } from 'react';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
class TinyMCETestResultElement extends Component {
render (){
console.log ("this.props.form0DataToDisplay " + this.props.form0DataToDisplay)// logs a changed string, as expected
return (
<div>
<div>results: {this.props.form0DataToDisplay}</div>
</div>
)
}
}
function mapStateToProps(state){
//whatever gets returned will show up as props inside of
return{
form0DataToDisplay: state.tinyMceTestData
}
}
export default connect( mapStateToProps, null)(TinyMCETestResultElement )
Math.random() in render block is the reason of such components behaviour.
React will rerender component only in case of it's state or props was changed. There is no updated props/state in your code sample, so component rendered only ones.
You can create variable in store for random value and update it with Math.random() into reducer. Then use it in your component as props and all wonna be ok.
It's probably because Redux's connected component is implementing shouldComponentUpdate for you, and it sees that your props don't change. As a result it won't update that component for you.
You can read about it here:
Redux Docs: http://redux.js.org/docs/basics/UsageWithReact.html
"...we suggest instead generating container components with the React Redux library’s connect() function, which provides many useful optimizations to prevent unnecessary re-renders. (One result of this is that you shouldn’t have to worry about the React performance suggestion of implementing shouldComponentUpdate yourself.)"
Twitter: https://twitter.com/dan_abramov/status/719723707124604928
A quick fix would probably be to implement shouldComponentUpdate to always return true, overriding Redux's implementation. Or better, having your props change everytime you get a new random number.
I should have mentioned that I was using a tiny mce component as the source of the change in state. If anyone comes across this question, there seemed to be an issue with loading that component, which could be fixed by re-rendering after initial load. I added this code to the tiny mce component to fix it. Timer may not be necessary.
componentDidMount(){
var that = this;
setTimeout(function(){
that.forceUpdate();
}, 1)
}