How to keep on adding the component on react state change.? - reactjs

I have a simple requirement where there is a successBar component
<successBar msg={"message"}/>
this one I want to insert to the dom on some state change. lets say we have a state,
successMessage, if we set a message in this state, then we need to how the success bar
like:-
{
this.state.successMessage && <SuccessBar msg={this.state.successMessage} />
}
the above code works,
here the main requirement is when the successMessage is updated it should add a new <Successbar /> and not replace the previous, bar.
and I don't want to track the previous success msg.
the <SuccessBar /> component will dismiss itself after a few seconds.
how to achieve this, in react.

You can have an Array with the SuccessBar components you want to render, and push to that array on every successMessage change.
Like this:
import { useState, useEffect } from "react";
function SuccessBar({ msg }) {
return <div>{msg}</div>;
}
export default function App() {
const [successMessage, setSuccessMessage] = useState("");
const [successComponents, setSuccessComponents] = useState([]);
useEffect(() => {
if (successMessage) {
setSuccessComponents((prevArray) => [
...prevArray,
<SuccessBar msg={successMessage} />
]);
}
}, [successMessage]);
return (
successComponents.map((Component) => Component)
);
}

Related

React Context value gets updated, but component doesn't re-render

This Codesandbox only has mobile styles as of now
I currently have a list of items being rendered based on their status.
Goal: When the user clicks on a nav button inside the modal, it updates the status type in context. Another component called SuggestionList consumes the context via useContext and renders out the items that are set to the new status.
Problem: The value in context is definitely being updated, but the SuggestionList component consuming the context is not re-rendering with a new list of items based on the status from context.
This seems to be a common problem:
Does new React Context API trigger re-renders?
React Context api - Consumer Does Not re-render after context changed
Component not re rendering when value from useContext is updated
I've tried a lot of suggestions from different posts, but I just cannot figure out why my SuggestionList component is not re-rendering upon value change in context. I'm hoping someone can give me some insight.
Context.js
// CONTEXT.JS
import { useState, createContext } from 'react';
export const RenderTypeContext = createContext();
export const RenderTypeProvider = ({ children }) => {
const [type, setType] = useState('suggestion');
const renderControls = {
type,
setType,
};
console.log(type); // logs out the new value, but does not cause a re-render in the SuggestionList component
return (
<RenderTypeContext.Provider value={renderControls}>
{children}
</RenderTypeContext.Provider>
);
};
SuggestionPage.jsx
// SuggestionPage.jsx
export const SuggestionsPage = () => {
return (
<>
<Header />
<FeedbackBar />
<RenderTypeProvider>
<SuggestionList />
</RenderTypeProvider>
</>
);
};
SuggestionList.jsx
// SuggestionList.jsx
import { RenderTypeContext } from '../../../../components/MobileModal/context';
export const SuggestionList = () => {
const retrievedRequests = useContext(RequestsContext);
const renderType = useContext(RenderTypeContext);
const { type } = renderType;
const renderedRequests = retrievedRequests.filter((req) => req.status === type);
return (
<main className={styles.container}>
{!renderedRequests.length && <EmptySuggestion />}
{renderedRequests.length &&
renderedRequests.map((request) => (
<Suggestion request={request} key={request.title} />
))}
</main>
);
};
Button.jsx
// Button.jsx
import { RenderTypeContext } from './context';
export const Button = ({ handleClick, activeButton, index, title }) => {
const tabRef = useRef();
const renderType = useContext(RenderTypeContext);
const { setType } = renderType;
useEffect(() => {
if (index === 0) {
tabRef.current.focus();
}
}, [index]);
return (
<button
className={`${styles.buttons} ${
activeButton === index && styles.activeButton
}`}
onClick={() => {
setType('planned');
handleClick(index);
}}
ref={index === 0 ? tabRef : null}
tabIndex="0"
>
{title}
</button>
);
};
Thanks
After a good night's rest, I finally solved it. It's amazing what you can miss when you're tired.
I didn't realize that I was placing the same provider as a child of itself. Once I removed the child provider, which was nested within itself, and raised the "parent" provider up the tree a little bit, everything started working.
So the issue wasn't that the component consuming the context wasn't updating, it was that my placement of providers was conflicting with each other. I lost track of my component tree. Dumb mistake.
The moral of the story, being tired can make you not see solutions. Get rest.

How to to trigger useEffects on windows.variable Global Variable change

I am loading the two files and i have a variable called routes that i want to have changed base on a click from another component. I have a global variable called window.showhide thats boolen and another one window.route which is an object array. i want to toggle window.showhide from another component and have useEffect trigger. using window.showhide useEffects does not trigger. i just want to change window.route to route2 from another component. please help me figure this out.
import route1 from "./routes1"
import route2 from ".routes2"
window.showhide = false
window.route = route1
const routes = window.route
export default function App() {
useEffect(() => {
if(window.showhide){
routes = route2
} else {
routes = route1
}
}, [window.showhide]);
}
useEffect does not have the ability to listen for variables to change, and then cause a rerender of your component. Rather, your component has to already be rerendering due to something else, and then the dependency array decides whether or not to run the extra code found in the useEffect.
If you want to render a component in react, you need to set state. So the typical solution for your kind of problem is to have a state variable in App, and then pass down a function that lets a child set that state.
export default function App() {
const [routes, setRoutes] = useState(route1);
const showHide = useCallback((value) => {
setRoutes(value ? route1 : route2);
}, []);
return (
<ChildComponent showHide={showHide} />
);
}
// In the child:
function ChildComponent({ showHide }) {
return <div onClick={() => showHide(true)} />
}
If the components are very far removed from eachother, then passing down via props may be a pain, in which case you can use context instead:
const ShowHideContext = createContext(() => {});
export default function App() {
const [routes, setRoutes] = useState(route1);
const showHide = useCallback((value) => {
setRoutes(value ? route1 : route2);
}, []);
return (
<ShowHideContext.Provider value={showHide}>
<ChildComponent />
</ShowHideContext.Provider>
);
}
// Elsewhere:
function Example () {
const showHide = useContext(ShowHideContext);
return <button onClick={() => showHide(true)} />
}

useState not updating[NOT AN ASYNC ISSUE]

I'm new to react hooks so I'm practicing with showing and hiding a div when checking and unckecking a checkbox input. The problem is that the state updates on the main file where I have the function that handles it but in the file where I actually have the div it does not update so it does not hide or display.
File that handles the change of the state:
import {react, useState} from "react";
export const Checker = () => {
const [checked, setChecked] = useState(true)
const clickHandler = () => {
setChecked(!checked)
console.log(checked)
}
return {checked, clickHandler, setChecked}
}
File where the checkbox is located:
import React from "react";
import { Extras, Wrapper } from "./extras.styles";
import { Checker } from "../hooks/useCheckboxes";
const Extra = () => {
const {checked, setChecked, clickHandler} = Checker()
return <>
<Extras>
<Wrapper>
<input type= 'checkbox' onClick={clickHandler} checked = {checked} onChange={e => setChecked(e.target.checked)}></input>
</Wrapper>
</Extras>
</>
}
export default Extra;
File that contains the div i want to display and hide dynamically:
import house from '../../icons/house.png'
import { Wrapper } from "./foto.styles";
import { Checker } from "../hooks/useCheckboxes";
import { Inside, Middle} from "./foto.styles";
const Home = () => {
const {checked} = Checker()
return <>
<Wrapper>
<Inside>
<Middle>
{checked && <House src={house}/>}
</Middle>
</Inside>
</Wrapper>
</>
}
export default Home;
Some issues are:
Checker looks like you want it to be a custom hook, not a React component, so it should be called useChecker or something like that, not Checker
You have both a change handler and a click handler. You should only have one. If you want the new state to come from the checkbox, you should use e.target.checked. If you want the new state to flip the old state, use the clickHandler you defined in Checker.
You only need a fragment when enclosing multiple elements. If you only have one, you don't need a fragment.
Because state setters don't update the variable immediately, your console.log(checked) won't display the new value, but the old value - if you want to log the new value when it changes, use useEffect with a dependency array of [checked] instead.
const Extra = () => {
const { checked, clickHandler } = useChecker()
return (
<Extras>
<Wrapper>
<input type='checkbox'checked={checked} onChange={clickHandler} />
</Wrapper>
</Extras>
)
}
use it like that
const {checked, clickHandler, setChecked} = Checker()
Or if you want to be able to make custom names then you need to use an array instead of an object.
the function return value.
return [checked, clickHandler, setChecked]
the function call
const [checked, setChecked, clickHandler] = Checker()
and for convention follow react hooks naming rules by renaming the function to useChecker() instead of Checker()

next.js how to change parent state from child component without triggering a button?

I have a SlaTable component to calculate and show a table of time values.
Below this table, I want to show a diagram based on the calculated values of SlaTable.
How can I return values from SlaTable to use them in another component?
<SlaTable
times={times}
monthList={monthList}
balanceValue={balanceValue}
slaFilter={slaFilter}
billableFilter={billableFilter}
/>
<Diagram
labels={chartLabels}
values={chartValues}
/>
Thanks in advance
Frank
I think I found the answer.
I have to use useEffect inside my component. So my solution looks like this:
import { useState } from "react";
function Sla(props) {
const [chartData, setChartData] = useState([]);
const changeChartData = (arg) => {
setChartData(arg);
};
return (
<>
<SlaTable
times={times}
monthList={monthList}
balanceValue={balanceValue}
slaFilter={slaFilter}
billableFilter={billableFilter}
changeChartData={changeChartData}
/>
</>
)
}
And inside the SlaTable component it's like this:
import { useEffect } from "react";
function SlaTable(props) {
const changeChartData = props.changeChartData;
const monthList = props.monthList;
let totalMonth = [];
// ----------------------------------------
// fill total month with zeros
// ----------------------------------------
monthList.forEach(() => {
totalMonth.push(0);
});
// call the changeChartData function when component
// finished rendering
useEffect(() => {
changeChartData(totalMonth);
}, [totalMonth.length]);
return (
<>
HTML output
</>
);
}
If I would not use useEffect inside the component, I would get an error that I cannot update a component while rendering a different component

How to control the order of rendering components in React?

There is a page contains a booking list and a popup window(A modal with survey questions). To reduce the impact on booking list loading time, I want to render the modal component after the booking list be completely loaded.
ps.there are network data request in both <BookingList/> and <Modal/>.
How should I do with React?
Thanks for help.
export default function Body() {
return (
<>
<BookingList .../>
<Modal .../>
</>
);
}
You can conditionally render the Modal component after the BookingList fetches the results.
For that, you'd need a state variable in the parent component of BookingList and Modal. Code sandbox https://codesandbox.io/s/romantic-cookies-zrpit
import React, { useEffect, useState, useCallback } from "react";
const BookingList = ({ setLoadedBookingList }) => {
useEffect(() => {
setTimeout(() => {
setLoadedBookingList();
}, 1000);
}, [setLoadedBookingList]);
return <h2>BookingList</h2>;
};
const Modal = () => <h1>Modal</h1>;
export default function App() {
const [loadBookingList, setLoadBookingList] = useState(false);
const setLoadedBookingList = useCallback(() => {
setLoadBookingList(true);
}, []);
return (
<div className="App">
<BookingList setLoadedBookingList={setLoadedBookingList} />
{loadBookingList && <Modal />}
</div>
);
}
You can use react hooks useState() and useEffect():
export default function Body() {
// `isLoaded` is a variable with false as initial value
// `setLoaded` is a method to modify the value of `isLoaded`
const [isLoaded, setLoaded] = React.useState(false)
React.useEffect(() => {
// some method used in loading the resource,
// after completion you can set the isLoaded to true
loadBookingList().then(loaded => setLoaded(true));
},
// second argument to `useEffect` is the dependency which is out `setLoaded` function
[setLoaded]);
return (
<>
// conditional rendering based on `isLoaded`
{isLoaded && <BookingList .../>}
<Modal .../>
</>
);
}

Resources