Home > Blockchain >  Re-render component on top level
Re-render component on top level

Time:10-03

I'm getting data from server in top level component and when I do get some specific data I want to rerender App component, so it has these new data, that came from server, but I can't think of how, because I can't use f.e. hooks on top level component. I'm aware, that I could just move all my listeners to App component and just do all the things there, but I don't like that it would send 4 times more request from server, because it's rerendering at the every state.

So I wanted to ask if there is a possibility to have my listeners at the top level component and just rerender the child components.

Here is my top level component code

import React from 'react';
import ReactDOM from 'react-dom';
import { GlobalStyle } from './components/global_styles';
import App from './components/App';

const ws = new WebSocket("ws://localhost:3001");
var token = JSON.parse(localStorage.getItem('loginToken') || '{}');

ws.onmessage = ({ data }) => {
  const parsedData = JSON.parse(data)

  switch (parsedData.type) {
    case 'login-success':
      console.log('logged in');
      token = parsedData.user;
      break;

    case 'login-fail':
      console.log(parsedData.error);
      break;
  }
};

ReactDOM.render(
  <React.StrictMode>
    <GlobalStyle />
    <App ws={ws} token={token} />
  </React.StrictMode>,
  document.getElementById('root')
);

Specifically I'm talking about the 'token' variable, whenever it changes, it should rerender App component.

CodePudding user response:

If you want changes to token trigger a rerender, it must be made a state variable.

One pattern that might fit your needs is using a Context that saves the token and using it in your App component

I would imagine it would be something like that

const TokenContext = React.createContext()

export const TokenProvider = ({children}) => {
    const [token, setToken] = useState(JSON.parse(localStorage.getItem('loginToken') || '{}'));

    useEffect(() => {
      const ws = new WebSocket("ws://localhost:3001");
      ws.onmessage = ({ data }) => {
  const parsedData = JSON.parse(data)

  switch (parsedData.type) {
    case 'login-success':
      console.log('logged in');
      setToken(parsedData.user);
      break;

    case 'login-fail':
      console.log(parsedData.error);
      break;
  }
};
    return () => {/*whatever you need to do for cleanup, e.g. closing the connection*/}
     },[]);


    return (<TokenContext.Provider value={token}>{children}</TokenContext.Provider>)



}


export const useToken = () => useContext(TokenContext)

In your top level code add (after importing of course)

ReactDOM.render(
  <React.StrictMode>
    <TokenProvider>
    <GlobalStyle />
    <App ws={ws} token={token} />
    </TokenProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

And now you can utilize the useToken hook wherever you need the token like const token = useToken()

Alternatively, you can use a global state manager like Redux or MobX or one of the thousand others that exist for React and I can no longer keep track of

CodePudding user response:

inside your App component simply use an useEffect hook with token as a dependency as

useEffect(()=>{ /* token changed do something */ },[token])

  • Related