component re-render after every request, usememo not working - reactjs

I am getting a list of tasks from API, every request fetch 15 tasks, when I click on the task it shows me a modal popup, and the data in that modal blinks when the next request hits, and it re-renders the entire page. I want not to blink data in the modal which are already fetched. data in modal comes from the form.io
I also tried several react/usememo solutions like
Widget.js
return (
<div className="dashboard_widget_card box-shadow p-3 card draggable dropzone ui-droppable " style={{ wordWrap: 'anywhere', fontSize: '14px', color: 'grey', borderRadius: '20px' }} >
<h4 style={{
fontsize: '15px',
color: ' #585858',
fontweight: '500',
}}>My Tasks</h4>
{DataCombines.map((element) => {
const datetype = moment(element.estimated_completion_date).format(
"DD-MM-YYYY"
);
if (datetype === tomorrow) {
globalvariable = "Tomorrow";
} else if (datetype === today) {
globalvariable = "Today";
} else {
globalvariable = "Other";
}
return (
<div style={{ marginRight: '20px' }}>
{DataCombines ?
<Card taskdata={element} taskTime={globalvariable} feths={FetchAll} /> :
<Backdrop
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
>
<CircularProgress color="inherit" />
</Backdrop>
}
</div>
);
})}
</div>);
Card.js
<div onClick={handleClickOpen} key={taskdata._id} >
<p
style={{
textTransform: "capitalize",
wordwrap: " anywhere",
fontSize: "14px",
fontWeight: "600",
color: "#313332",
}}
>
{taskdata.task_title}
</p>

Related

How can I avoid re-render when props change in a modal in React?

I have a problem. I want to put a form inside a modal in react, and when the user click the button accept submit the data to a given url. But I want the modal be generic enough to wrap many forms but doing this the modal have to receive some parameters and every time the parameters change, the modal re-renders.
I create a custom hooks where I return the form and the data I extract from the form. Then I pass the form as a child of the modal component and the data as prop. Then when the user clic the accept button, the data will submit to the url.
But the form every time I write in it, re-render the modal. I can put the modal code inside every form component and it will work, but it's an ugly solution, the code won't be clean and won't be as efficient as it can. Hope you can help me.
The Modal Code:
`
const ModalDialogForm = (props) => {
const { title = "Modal", isFullScreen = true, open, setOpen, children = "", cleanElements = () => { }, data = "", content } = props;
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
const cleanForm = () => {
document.getElementById("modal-form").reset();
}
return (
<>
<Dialog fullScreen={isFullScreen} open={open} TransitionComponent={Transition} style={{
color: "transparent",
display: "flex", margin: "auto",
justifyContent: "center", flexDirection: "column", borderRadius: "10px"
}}>
<AppBar sx={{ position: 'relative' }} style={{ backgroundColor: "white" }} elevation={0}>
<Toolbar variant='regular'>
<Typography sx={{ ml: 2, flex: 1 }} variant="h6" component="div" style={{ color: "black" }} >
{title}
</Typography>
<IconButton edge="start" color="inherit" onClick={() => setOpen(false)} aria-label="close">
<CancelIcon style={{ color: "black" }} />
</IconButton>
</Toolbar>
</AppBar>
<Paper style={{ backgroundColor: "rgb(249, 249, 249)", height: "100%", borderRadius: "0px" }} elevation={1}>
<form id="modal-form">
{children}
{content ? content() : ""}
</form>
</Paper>
<AppBar sx={{ position: 'relative' }} style={{ backgroundColor: "white" }} elevation={0}>
<Toolbar style={{ display: "flex", justifyContent: "flex-end" }}>
<Button style={{ backgroundColor: "green", color: "white" }} onClick={() => { console.log(data); }}>
Aceptar
</Button>
<Button style={{ color: "black" }} onClick={() => { cleanForm(); cleanElements(); }}>
Limpiar
</Button>
<Button style={{ color: "black" }} onClick={() => setOpen(false)}>
Cerrar
</Button>
</Toolbar>
</AppBar>
</Dialog>
</>
)
}
`
The Page where I call the modal:
`
const renderModal = () => (
<>
<ModalDialogForm isFullScreen={false} title="Adicionar Idioma" open={modalOpened} setOpen={setModalOpened} data={data}>
{getForm()}
</ModalDialogForm>
</>
)
useEffect(() => {
setModal(
modalOpened ? (<>
{renderModal()}
</>
) : (
<></>
)
);
}, [modalOpened, data]);
return (
<div>
<IdiomaTable canInsert={insertar} canModify={modificar} canDelete={eliminar} openModal={() => { setModalOpened(true); }} />
{modal}
</div>
)
`
I solve the problem. It is a temporary solution until I find a better one but works. Just removed the transition property of the Dialog component then the modal re-render but because don't have the transition the UI looks good. It is less fancy, but functional.

How to use MessageBird SMS with a form in React?

When I use MessageBird with a phone number that was hardcoded, everything goes well. The message is sent correctly and I am satisfied.
The problem is when I try to send an SMS with a form where the user needs to enter the phone number.
I am using React Hooks.
function Account() {
const { authenticate, isAuthenticated, account, chainId, logout } =
useMoralis();
const [isModalVisible, setIsModalVisible] = useState(false);
const [isAuthModalVisible, setIsAuthModalVisible] = useState(false);
const [phoneNumber, setPhoneNumber] = useState();
function phoneNumberFromForm (phone) {
setPhoneNumber (phone);
console.log(" phone: ", phoneNumber);
}
if (!isAuthenticated || !account) {
return (
<>
<div onClick={() => setIsAuthModalVisible(true)}>
<p style={styles.text}>Authenticate</p>
</div>
<Modal
visible={isAuthModalVisible}
footer={null}
onCancel={() => setIsAuthModalVisible(false)}
bodyStyle={{
padding: "15px",
fontSize: "17px",
fontWeight: "500",
}}
style={{ fontSize: "16px", fontWeight: "500" }}
width="340px"
>
<div
style={{
padding: "10px",
display: "flex",
justifyContent: "center",
fontWeight: "700",
fontSize: "20px",
}}
>
Connect Wallet
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
{connectors.map(({ title, icon, connectorId }, key) => (
<div
style={styles.connector}
key={key}
onClick={async () => {
try {
if (connectorId) {
await authenticate({ provider: connectorId });
window.localStorage.setItem("connectorId", connectorId);
} else {
await authenticate();
}
setIsAuthModalVisible(false);
} catch (e) {
console.error(e);
}
}}
>
<img src={icon} alt={title} style={styles.icon} />
<Text style={{ fontSize: "14px" }}>{title}</Text>
</div>
))}
</div>
</Modal>
</>
);
}
return (
<>
<div style={styles.account} onClick={() => setIsModalVisible(true)}>
<p style={{ marginRight: "5px", ...styles.text }}>
{getEllipsisTxt(account, 6)}
</p>
<Blockie currentWallet scale={3} />
</div>
<Modal
visible={isModalVisible}
footer={null}
onCancel={() => setIsModalVisible(false)}
bodyStyle={{
padding: "15px",
fontSize: "17px",
fontWeight: "500",
}}
style={{ fontSize: "16px", fontWeight: "500" }}
width="400px"
>
Account
<Card
style={{
marginTop: "10px",
borderRadius: "1rem",
}}
bodyStyle={{ padding: "15px" }}
>
<Address
avatar="left"
size={6}
copyable
style={{ fontSize: "20px" }}
/>
<div style={{ marginTop: "10px", padding: "0 10px" }}>
<a
href={`${getExplorer(chainId)}/address/${account}`}
target="_blank"
rel="noreferrer"
>
<SelectOutlined style={{ marginRight: "5px" }} />
View on Explorer
</a>
</div>
<div>
<PhoneInput enableAreaCodeStretch onChange={phone => phoneNumberFromForm({phone})}/>
</div>
<Button
size="small"
type="primary"
style={{
width: "50%",
marginTop: "10px",
borderRadius: "0.5rem",
fontSize: "12px",
fontWeight: "500",
}}
onClick={async () => {
console.log(" phone number on form", phoneNumber);
messagebird.messages.create({
originator : '67528923',
recipients : '$phoneNumber.phone',
body : 'testing this function. '
},
function (err, response) {
if (err) {
console.log("ERROR:");
console.log(err);
} else {
console.log("SUCCESS:");
console.log(response);
}
});
}}
>
Verify phone number
</Button>
</Card>
<Button
size="large"
type="primary"
style={{
width: "100%",
marginTop: "10px",
borderRadius: "0.5rem",
fontSize: "16px",
fontWeight: "500",
}}
onClick={async () => {
await logout();
window.localStorage.removeItem("connectorId");
setIsModalVisible(false);
}}
>
Disconnect Wallet
</Button>
</Modal>
</>
);
}
export default Account;
Can anyone tell me what I am doing wrong?
This is the error I am getting.
Error: api error(s): no (correct) recipients found (code: 9, parameter: recipient)
I believe it must have something to do to how I am calling the recipient's number.
I am using this line.
recipients : '$phoneNumber.phone',
I am using the code above, but is it the correct way to call that object?
You guessed it right, the problem is in the place where you call MessageBird API.
messagebird.messages.create({
originator : '67528923',
recipients : '$phoneNumber.phone',
body : 'testing this function. '
},
recipients should be array of strings (phone numbers), e.g.:
{
'originator': 'YourBrand',
'recipients': [
'31612345678'
],
'body': 'Hello, world!'
}
So I think in your code you need to change it to:
messagebird.messages.create({
originator : '67528923',
recipients : [phoneNumber.phone],
body : 'testing this function. '
},

Const component cannot read property of undefined even though it is a prop?

I have a parent? class that hosts a random question and different types of user input that depend on the type of question.
3 clickable buttons that change color on click
an input box
class Parent extends Component {
state = {
buttonColors: ["white", "white", "white"],
questionType: 0,
avg: 0,
numbers: [],
answer: "",
number: 0,
showAns: false,
current: "",
etc....
}
// This part basically handles clicking of 3 buttons
clickedAnswer(userAnswer) {
// 0 is (>) // 1 is (=) 1 is (<)
let colors = this.state.buttonColors;
let guess = this.state.current;
if (!guess.includes(1)) {
//Hasn't Guessed Yet -Action- Select Clicked button
//Change color of the Guessed button
colors[userAnswer] = "#d0f0c0";
guess[userAnswer] = 1;
} else {
//Clicked Previous Answer -Action- Unselect Clicked button
colors = ["white", "white", "white"]; //Reset Colors
colors[userAnswer] = "#d0f0c0";
guess = [0, 0, 0]; // Reset Guess
guess[userAnswer] = 1;
}
this.setState({
current: guess,
buttonColors: colors,
});
}
render() {
return (
<RenderInput
questionType={this.state.questionType}
answer={this.state.answer}
buttonColors={this.state.buttonColors}
clickedAnswer={this.clickedAnswer}
handleChange={this.handleChange}
current={this.state.current}
showAns={this.state.showAns}
/>
)
}
and then I have a const Render at the bottom of my file which dynamically renders the input type depending on the questionType.
const RenderInput = (props) => {
switch (props.questionType){
case 0: case 1: case 2: case 3:
return (
<Row style={{ paddingBottom: "50px", paddingTop: "50px" }}>
<Col style={{height: 100, textAlign: "right"}}>
<button
id="btn1"
onClick={() => props.clickedAnswer(0)}
style={{
width: "200px",
height: "80px",
backgroundColor:
props.showAns && props.answer[0] === 1
? "red"
: props.buttonColors[0],
}}
>
<span
style={{ fontFamily: "courier", fontSize: "35px" }}
>
{"Higher"}
</span>
</button>
</Col>
<Col style={{ height: 100, textAlign: "center" }}>
<button
id="btn2"
onClick={() => props.clickedAnswer(1)}
style={{
width: "250px",
height: "80px",
backgroundColor:
props.showAns && props.answer[1] === 1
? "red"
: props.buttonColors[1],
}}
>
<span
style={{ fontFamily: "courier", fontSize: "35px" }}
>
{"Unchanged"}
</span>
</button>
</Col>
<Col style={{height: 100, textAlign: "left"}}>
<button
id="btn3"
onClick={() => props.clickedAnswer(2)}
style={{
width: "200px",
height: "80px",
backgroundColor:
props.showAns && props.answer[2] === 1
? "red"
: props.buttonColors[2],
}}
>
<span
style={{ fontFamily: "courier", fontSize: "35px" }}
>
{"Lower"}
</span>
</button>
</Col>
</Row>
)
case 4: case 5:
return (
<p
style={{
fontSize: 25,
textAlign: "center",
fontFamily: "courier",
fontWeight: "bold",
paddingTop: "10px",
}}
>
<input
type="text"
value={props.current}
onChange={props.handleChange}
id="input1"
autoComplete="off"
maxLength="8"
style={{
color: !props.showAns ? "black" : "red",
fontSize: 55,
fontFamily: "courier",
fontWeight: "bold",
width: "280px",
height: "85px",
textAlign: "center",
}}
/>
</p>
)
}
}
However when I try to click the button the change the color, I get an error saying
cannot read property 'buttonColor' of undefined
How do I fix this? I basically need the child? or const component to return an action user clicked button 1/2/3 to the method clickedAnswer which changes the button color based on the button # and then send that updated color scheme back to the const and re-render the input section to reflect the color update.
When you call clickedAnswer={this.clickedAnswer}, the this reference is null within the method. Replace it with clickedAnswer={this.clickedAnswer.bind(this)} to bind to the current object so that it will have access to the state.
You can read about the bind method here: Function.prototype.bind()

How to import just one function from different file into other?

I have a layout file where I made footer and navigation and I insert these two functions in Layout const (code below). In the new file, I just need the Navigation function so how I can insert it without a footer? Because when I write in my new file import Navigation from "../components/layout" and the in code insert I've got error...
const Layout = ({ children }) => {return (
<div>
<Navigation></Navigation>
<Global
styles={{
html: {
backgroundColor: "#fff",
color: "#111",
fontFamily: `'Poppins', sans-serif`,
fontSize: 14,
[Screen.S]: {
fontSize: 16,
},
[Screen.M]: {
fontSize: 18,
},
[Screen.L]: {
fontSize: 20,
},
},
a: {
color: "unset",
},
}}
/>
{children}
<Footer></Footer>
</div>
)
}
function Navigation() { const [navbarOpen, setNavbarOpen] = useState(false) return (
<header
css={{
width: "100%",
maxWidth: "100%",
padding: "0 24px",
position: "fixed",
background: "#fff",
boxShadow: "0 0 0.35rem rgba(0,0,0,.25)",
zIndex: "100",
top: 0,
}}
>
<div
css={{
gridAutoFlow: "column",
minHeight: "4.5rem",
display: "grid",
maxWidth: 1200,
margin: "0 auto",
gridTemplateColumns: "auto 1fr",
alignItems: "center",
paddingLeft: 35,
}}>
<Link to="/ ">
<img style={{ height: "2.5rem" }} src={logo}/>
</Link>
<Toggle
navbarOpen={navbarOpen}
onClick={() => setNavbarOpen(!navbarOpen)}
>
{navbarOpen ? <Hamburger open /> : <Hamburger />}
</Toggle>
{navbarOpen ? (
<NavBoxIcons>
<NavbarSocialLinks />
</NavBoxIcons>
) : (
<NavBox open>
<div>
<HeaderLink>About</HeaderLink>
<HeaderLink>Blog</HeaderLink>
</div>
<div>
<NavbarLinks />
</div>
</NavBox>
)
}
</div>
</header >
)
}
function Footer() { return (
<footer
css={{
padding: "6rem 2rem",
fontSize: "1rem",
minHeight: 160,
fontFamily: "sans-serif",
...Css.container,
}}
>
<div
css={{
display: "flex",
flexDirection: "column",
marginBottom: "3.6rem",
}}
>
<div
css={{
fontSize: "1.2rem",
display: "grid",
gridGap: "0.8rem",
}}>
<a>
<span>Privacy police</span>
</a>
</div>
</div>
<div
css={{
display: "grid",
gridTemplateColumns: "1fr auto",
alignItems: "center",
fontWeight: "lighter",
}}>
<div css={{ display: "flex", flexDirection: "column" }}>
<span>My Page</span>
</div>
</div>
</footer>
)
}
try exporting both Navigation and Footer like this
//at bottom of file
export {Navigation, Footer}
import individual component like this
import {Navigation} from 'components/layout'
or
import {Navigation,Footer} from 'components/layout'
lookup exporting in js

React: changing icon on mouseEnter using state. Icon stuck on "hover" state if I move the mouse too fast

I have a component with an unchecked checkbox icon. When hovering over the icon, I am displaying a checked version of the icon. I am using state to set the isHovered state to true when the mouse enters the div that contains the icon and to false when the mouse leaves the div. I do a conditional rendering in the div, using an unchecked icon if the isHovered state is false and a checked icon if isHovered is true.
My component is used multiple times in a row in my app and my issue is that if I move my mouse fast over the icons, some of them get stuck in the isHovered state true even if the mouse is not over them anymore.
Any suggestions to fix this behavior ?
Here is my code:
const [isHovered, setIsHovered] = useState(false);
const onMouseEnter = () => {
setIsHovered(true);
};
const onMouseLeave = () => {
setIsHovered(false);
};
return (
<div
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onClick={handleArchive}
style={{ display: "flex", alignItems: "center", cursor: "pointer" }}
>
{isHovered ? (
<CheckCircleIcon
style={{ color: "grey", fontSize: 20, marginRight: 10 }}
/>
) : (
<RadioButtonUncheckedIcon
style={{ color: "grey", fontSize: 20, marginRight: 10 }}
/>
)}
</div>
Solution 1:
const [isHovered, setIsHovered] = useState(false);
return (
<div
onMouseEnter={() => setIsHovered(!isHovered)}
onMouseLeave={() => setIsHovered(!isHovered)}
onClick={handleArchive}
style={{ display: "flex", alignItems: "center", cursor: "pointer" }}
>
{isHovered ? (
<CheckCircleIcon
style={{ color: "grey", fontSize: 20, marginRight: 10 }}
/>
) : (
<RadioButtonUncheckedIcon
style={{ color: "grey", fontSize: 20, marginRight: 10 }}
/>
)}
</div>
Solution 2: A simple css-only solution

Resources