How to re-render a map loop in JSX? - reactjs

I have a sidebar with buttons links that targets div id and URL ends with #id_name. Now I want to render data that matches #id_name in a map loop using this code:
<div>
{entries.map((item, index) => {
if (asPath.endsWith(`#${item.section}`))
return (
<div id={item.section} key={index}>
<h3>{item.title}</h3>
<p>{item.summary}</p>
</div>
);
})}
</div>
It works on refresh if #id_name matches item.section but if I click another link nothing happens even if item.section matches #id_name.
How can I re-render the map loop without refreshing or leaving the page when #id_name changes?

If you want to re-render to work
asPath or entries should be in useState or redux state.
I think asPath is more correct one for this case... try using useEffect and useState

I did figure it out without using a state. Instead of using Next Link or <a> on button links, I used push from useRouter. Weird how that one works.
const router = useRouter();
const handleHref = (link) => {
router.push(link);
};
<Botton onClick={() => handleHref(`#${String(item.section).replace(/ /g, "-")}`)}>{item.section}</Botton>

Related

Changing the React component state with same value on button click trigger re-render for the first two button clicks. Why UI re-rendering twice?

When I click on the 'Rerender UI' button then it prints in the console for the first two clicks. I think it should print in the console only for the first time when I click on the 'Rerender UI' button because on the button click the component state is changed so UI will re-render and the console log will be printed in the console. Why is it printing for the second click? StrictMode is off. See code:
export default function UseCallbackComp() {
const [stateVar, setStateVar] = useState<any>()
console.log("Parent Rerendered!")
return (
<>
<div>UseCallbackComp content</div>
<div>
<button
onClick={() => {
setStateVar(1)
}}
>
Rerender UI
</button>
</div>
</>
)
}
When I put the console log line inside useEffect like below it prints only for the first time 'ReRender UI' button is clicked which is the expected behaviour.
useEffect(() => {
console.log("Parent Rerendered!")
})
From the below two links I got to know whats the behaviour of react when useState is used:
stackoverflow question
gitHub discussion
There are two different cases for which useState behaves differently for same value.
Case 1: When useState used with same value as the initial value.
Result: No rerendering at all.
export default function LifecycleEvents() {
const [stateVar, setStateVar] = useState<any>(0)
console.log("Parent Rerendered!")
return (
<>
<button
onClick={() => {
setStateVar(0) //same value as the initial value
}}
>
Rerender UI
</button>
</>
)
}
Case 2: When useState used with different value first and then with the same value.
Result: First both Parent and child will be re-rendered. But for the second time, only the render function of Parent component will get called, Nothing else.
See code:
export default function LifecycleEvents() {
const [stateVar, setStateVar] = useState<any>(0)
console.log("Parent Rerendered!")
return (
<>
<button
onClick={() => {
setStateVar(1) //different value then initial value.
}}
>
Rerender UI
</button>
</>
)
}
Conclusion: Nothing to worry unless you have an expensive render method of the component. In that case use memo.

nextjs conditional jsx not re-rendering

Up in my component I have:
let isClicked = false;
Down where things are rendered I have:
<div className="relative">
{!isClicked ? (
<div className="relative">
1
</div>
) : (
<div className="relative">
2
</div>
)
}
</div>
The issue is nothing changes when the variable changes.
I can ensure the variable changes on the command line.
And the logic works if I change it and manually reload the page.
The issue is it won't re-render when the variables changes during the run time.
There are special variables in react that cause rerender on their change. These are state variables. Imagine the problem you will face if every variable change causes a rerender.
If this is a functional component you can make use of useState:
const [isClicked,setIsClicked] = useState(false);
.
.
//some method triggered by button click etc.
const onclick =() => {
setIsClicked(true);
}
.
.
Read : Link and Link

How to create a button that opens a new page with the option to return back to previous page [ReactJS

Right below the page you see a 'back to log' button. If someone clicks on that it will return to the left page. So in order to do so I thought using react router will do the job. But not sure how to fix that.Is there someone who can help me to point me to the right direction. Keep in mind that it will not open a new tab!
Link to working snippet to understand the bigger picture of my app. CodeSandBox snippet here
return (
<div>
{info.map((show: any) => {
console.log(show.show)
return (
<div key={show.show.id}>
<ReactMarkdown source={show.show.name}/>
{show.show.image && <img src={show.show.image.medium}/>}
{show.show.genres.map((showGenre: string, index: number) => {
return (
<div key={index}>
<ReactMarkdown source={showGenre}/>
</div>
)
})}
<div>
<Router>
<ul>
<li>
<Link to="/">See deta</Link>
</li>
</ul>
</Router>
</div>
</div>
)
})}
</div>
)
Check out this working example (I placed notes in each file):
https://codesandbox.io/s/modest-panini-hkzlv?file=/src/App.js
Overview:
there are several ways to do this
my suggestion is to use the history npm and create a history.js file
you will also need to use Router from react-router-dom
in your parent component, or in a Context provider, you can store your state
in the parent component, use react-router-dom Switch and Route to place routes
depending on implementation, conditionally render show route for async state update
in your search component, place all your Links using react-router-dom
on click Links should also update app's state of your specific selection
this selection gets passed to the show route/component
in the show component attach an on click that uses history.goBack and resets state
this might help you:
this.props.history.goBack();
it goes back to prev page

warning when using React Hook useCallback when setting state

I have a website with a super simple navigation.
It just displays different components based on the boolean value of a state property.
It's working fine, but I have this nagging warning that shows on the functions that handle clicks.
The warning is here:
useCallback does nothing when called with only one argument.
But I'm not sure why it's telling me that because my navigation is working.
Do I need to add something else to make it work better?
Thanks!
Here is my little component for navigation.
// creat state
const [showCreationPage, setCreationPage] = useState(true);
const [showDisplayPage, setDisplayPage] = useState(false);
// here is warning sign: useCallback does nothing when called with only one argument.
const handleCreationPage = useCallback(e => {setDisplayPage(false) || setCreationPage(true) });
const handleDisplayPage = useCallback(e => { setCreationPage(false) || setDisplayPage(true) });
// navigation buttons
<a href="#" onClick={handleCreationPage}>Create Beer</a>
<a href="#" onClick={handleDisplayPage}>Display Beer</a>
<div id="main">
<div>
{showCreationPage && <Create />}
</div>
<div>
{showDisplayPage && <Display />}
</div>
</div>
useCallback expects an array of dependencies as a second argument. That tells the memoization to update whenever the value of one of the dependencies is updated. If you never want the callback function to update, just pass an empty array.
Reference: https://reactjs.org/docs/hooks-reference.html#usecallback

System to manage reactjs applications

I get how to specify where to render the reactjs application by using the render method and specifying the html tag where it should be rendered.
What I do not understand is how you can have a list of react.js applications that is dynamically loaded into that same HTML tag.
For example there is a sidebar which is dynamically created to give a user a list of N number of react.js applications. When the user clicks on one of the links it loads that application into the HTML tag (div or whatever) container on the right.
I am sure this may be something easy but have been struggling with this concept for awhile.
Would appreciate any inputs anyone has on this.
If you truly had multiple full apps you wanted to swap out, you'd have to manually mount and unmount them. Something like a function like this, that unmounts the previous app, then mounts a new one. Example
function swapApp(App) {
const appNode = document.getElementById('app')
ReactDOM.unmountComponentAtNode(appNode)
ReactDOM.render(<App />, document.getElementById('app'))
}
But that would be a pain. So, typically, that menu and the content being changed are all part of the same react app. This app would render the menu, keep state about what item you clicked, and then render some components conditionally, depending on what was clicked.
Something like this example
function App() {
const [showingItem, setShowingItem] = React.useState(null)
return (
<>
<p><a href="#" onClick={() => setShowingItem('A')}>Show Item A</a></p>
<p><a href="#" onClick={() => setShowingItem('B')}>Show Item B</a></p>
{showingItem === 'A' ? <AppA /> : null}
{showingItem === 'B' ? <AppB /> : null}
</>
)
}

Resources