-1

So I have searched for solutions but I cant seem to find one that fits with what I am doing. Here is the structure of my website:

https://ibb.co/Xz27rgK

So as you can see I have my "NavBar" component outside of the Router because I always want it rendered. But I have a Dark mode toggle on the navbar, and when I click it I want it to update the refresh the Chart component (It is a react-chartjs-2 chart).

I know you can use setState(); to rerender, but how tell the Chart component to do that from the NavBar when I run the onClick(); function that I have inside of it?

DevinGP
  • 199
  • 2
  • 2
  • 10

1 Answers1

0

For one component to trigger a re-render of a sibling component, or a child of a sibling, they must trigger a re-render of some shared parent component. In this case it would make sense for all components to be children of a single root component since the theme should be consistent across the entire project, unless you have some specific use case.

Probably the easiest way to do this is to pass in a callback setTheme as well as a theme attribute from the topmost component. In the setTheme callback, you should call the setState of that topmost parent component, which will then trigger a re-rendering of every child component with the new theme.

Take a look here for a more detailed description of how to change the theme of react components.

joshmeranda
  • 3,001
  • 2
  • 10
  • 24
  • So would you recommend that I have the rest of the page as a child of the Navbar? Is that good practice? Or should is there another way to structure my project that I am not realizing. I apologize if this is a silly question as this is my first go at React. – DevinGP Aug 20 '20 at 22:04
  • I wouldn't have it under the navbar. Usually all react components are children of some root component that does nothing but provide some common state and components to every page like a header and footer, and potentially determine which other component(s) to render and delegate everything from there. You can think of the root component as a blank canvas, upon which you paint the react components. So navbar could be one of those common components, and the root component would save the `theme` state. – joshmeranda Aug 20 '20 at 22:08
  • Okay, so I have a function in a parent component that imports the NavBar and Home, of which home imports the chart component and displays it. I used `this.setState(this.state);` in the parent object but it did not reload the chart object. I tested this by trying a `console.log()` in the chart component but it only gets output from the initial load. I apologize if this is a simple error I am making or misunderstanding, thanks for your help. – DevinGP Aug 20 '20 at 22:47
  • And each of those components are taking the `theme` attribute? If they don't, then no state is being updated for them and that entire branch of the DOM will be ignored in the rerender and will remain the same – joshmeranda Aug 20 '20 at 22:53
  • If I understand what you are suggesting, I believe so. I have View.jsx, which passes the theme element from its state to Home.jsx, which then passes it to Chart.jsx. The function to change the theme is in View.jsx, which gets triggered when a button from NavBar gets clicked. NavBar.jsx is also a child of View.jsx. When the function is called, it calls `this.setState(this.state);` which once again is in Views.jsx. – DevinGP Aug 20 '20 at 23:08
  • You can read more [here](https://reactjs.org/docs/react-component.html#setstate) about how state is modified. You are changing the value of the `theme` attribute in `this.state` correct? And you have the debugging console.log in either the `setState` callback parameter or in the component's `componentDIdUpdate` method correct? – joshmeranda Aug 20 '20 at 23:18
  • Yes I am, I looked at your link and copied how they were doing it, I have the `ThemeContext.tsx` which is what wraps around my whole page in View.jsx. From there, I store the function `setTheme()` which I imported from the ThemeContext file in the state and pass it as a prop to the navbar where the button is, so that when it is pressed it calls it. I also pass it to the Home component which is a sibling of NavBar. Finally from Home I pass it to the Chart component. Under the state declaration, I have `componentDidUpdate() {console.log("Test")}` but it only prints out when the page first loads. – DevinGP Aug 20 '20 at 23:47
  • Are you trying to store the theme in the child component state or in the props? If in the child state, the stat will not update when it re-renders, but the theme should update when you access the theme from the props directly. You can check if the props are being updated with the `componentWillReceiveProps` function – joshmeranda Aug 21 '20 at 00:07
  • I am passing it as a prop, so to get the function I am doing `this.props.theme`. I see that the Chart component is receving it because when I console.log that I see a reference to that function being printed out. I am putting that console.log() in the constructor, which to my understanding is when the component first loads. the only thing I am storing the Chart state is data to populate the chart. I am just doing a message in `componentDidUpdate();` which is not running. I tried componentDidUpdate in the parent above Chart, which is also receiving the function as a prop. It didnt run either. – DevinGP Aug 21 '20 at 00:12
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/220185/discussion-between-joshmeranda-and-devingp). – joshmeranda Aug 21 '20 at 00:26