2

I am using a Context provider (AccountProvider.js) as a means of providing account details (as well as notifications through a socket.io connection) down to all its children components. The notifications and user objects load fine into AccountProvider component and does actually keep updating its own state.

Knowing that if a parent component's state changes, this should mean that the children of the parent component all should also re-render right? Apparently it is not the case here and I can not seem to figure out why.

Is there any solution to this issue? Perhaps a need for force updating children components?

AccountProvider.js

import React, { Component } from 'react'
import axios from 'axios'
import socketIOClient from "socket.io-client";
import config from '../config/config'

export const myContext = React.createContext();

export default class AccountProvider extends Component {

    state = {
        data: []
    }

    async componentDidMount() {
        const auth_token = localStorage.getItem('jwt token')
        const header = 'Bearer ' + auth_token;
        const res = await axios.get(config.API_URL+'/api/account', {headers: {Authorization:header}});
        const blob = await axios.get(config.API_URL+'/' + res.data.image, {headers: {Authorization:header}, responseType: "blob"});
        var user = res.data;
        user["image"] = URL.createObjectURL(blob.data);

        this.setState({
            data: {user}
        });

        const io = socketIOClient(config.REDIS_URL, { query: {jwt: localStorage.getItem('jwt token')} });

        io.on("event", data => {
            if (data !== this.state.notifications){
                var curr_data = this.state.data;
                curr_data["notifications"] = data;
                this.setState({data: curr_data});
            }
        });

        io.on("reconnect", () => {
            io.emit("jwt", localStorage.getItem('jwt token'));
        })
    }


    render() {
        return (
            <myContext.Provider value={this.state.data}>
                {this.props.children}
            </myContext.Provider>
        )
    }
}

App.js (render)

  <AccountProvider>
    <Route
      path="/dashboard"
      render={({ match: { url } }) => (
                <Dashboard>
                  <Switch>
                    <Route path={`${url}/Account`} component={Account} exact />
                    <Route path={`${url}/Deposits`} component={Deposits} exact />
                    <Route path={`${url}/Notifications`} component={Client} exact />
                    <Route path={`${url}/`} component={Account} exact /> */}
                    <Route component={Page404Dashboard} />
                  </Switch>
                </Dashboard>
      )}/>
  </AccountProvider>

Dashboard.js

import React, { Component } from 'react'
import AccountContent from './AccountContent';
import PendingCard from '../PendingCard';
import {myContext} from '../../../AccountProvider'

class Dashboard extends Component {
    render() {
        // The following should log notifications after AccountProvider rerenders
        console.log(this.context.notifications && this.context.notifications);
        return (
            <>
                { this.props.hasCard ? <AccountContent/> : <PendingCard/> }
            </>
        )
    }
}

Dashboard.contextType = myContext;
export default Dashboard;
Yilmaz
  • 4,262
  • 6
  • 24
  • 52
Vitalynx
  • 757
  • 1
  • 6
  • 14
  • "this should mean that the children of the parent component all should also re-render right?" No. – Dennis Vash Jun 16 '19 at 23:39
  • Possible duplicate of [Does new React Context API trigger re-renders?](https://stackoverflow.com/questions/50817672/does-new-react-context-api-trigger-re-renders) – Austin Greco Jun 16 '19 at 23:39

1 Answers1

2

change:

var curr_data = this.state.data;
curr_data["notifications"] = data;
this.setState({data: curr_data});

with:

var curr_data = Object.assign({}, this.state.data);
curr_data["notifications"] = data;
this.setState({data: curr_data});

you are not really updating the state with the first case

UXDart
  • 2,222
  • 11
  • 12
  • This worked, I am curious as to why the first case doesn't update the state though – Vitalynx Jun 17 '19 at 00:04
  • great! it doesn't work, because you get curr_data and then change it... but curr_data is the same object as data... so when you setState "data" didn't change... so there is no new render – UXDart Jun 17 '19 at 00:05