0

I'm passing a function to another component in the link. In another component, I make a query to api, when the query is executed I go back to the previous page and execute the "openFromLogin" function. The function executes because it returns console.log, but the variable is still false.

I want to do so that after logging in and redirecting it automatically opens the modal.

Please help, thanks :)

import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import Modal from 'react-modal';

function ProductSidebarOne(props) {
  const [openPricing, setOpenPricing] = useState(false);
  
  const openFromLogin = () => {
    setOpenPricing(true);
    console.log("done");
  }
  console.log(openPricing);

  return (
    <>
      <Link to={{ pathname: `/login`, state: { from: props.location.pathname }, openFromLogin }} className="font-orange font-semibold">Log in</Link>
      <Modal
        isOpen={openPricing}
        shouldFocusAfterRender={false}
        className="pricing-popup"
        closeTimeoutMS={10}
      >
        <div className="modal-dialog modal-dialog-centered" role="document">
          <div className="modal-content">
            <div className="modal-body">
              <button type="button" className="close" aria-label="Close" style={{ position: 'absolute', right: '0', top: '0' }}>
                <span aria-hidden="true">&times;</span>
              </button>
            </div>

            <div className="modal-footer">
              <button type="button" className="btn btn-link btn-sm">Close</button>
              <button type="submit" className="btn btn-primary btn-sm">Send</button>
            </div>
          </div>
        </div>
      </Modal>
    </>
  )
}

export default ProductSidebarOne;
import React, { useState } from 'react';
import axios from 'axios';

import { setUserSession } from '../../../../utils';

function Login(props) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const openFromLogin = props.location.openFromLogin;

  const handleLogin = (e) => {
    e.preventDefault();

    axios.post("api url", {
      email: email,
      password: password
    })
    .then(response => {
      setUserSession(response.data);
      props.history.push(props.location.state.from, openFromLogin());
    });
  }

  return (
    <div className="login-page">
      <form onSubmit={handleLogin} className="mb-0">
        <input type="text" className="form-control" value={email} onChange={e => setEmail(e.target.value)} />
        <input type="password" className="form-control" value={password} onChange={e => setPassword(e.target.value)} />
        <div className="form-footer">
          <button type="submit" className="btn btn-primary">Log in</button>
        </div>
      </form>
    </div>
  )
}

export default Login;
andrzej
  • 3
  • 1

1 Answers1

0

Duplicated in Pass props in Link react-router

AFAIK you cannot do that with Link. You would have to pass either path or query parameters, since Link is basically just an anchor to an url.

What you could do instead is setting up a "global" state with context which gets manipulated after successfully logging in. Your ProductSidebarOne could then subscribe, "use", that context and react to it, if it fulfills the requirements.

Example: Setup a AuthenticationContext and set loggedIn to true after successfully logging in. useContext for AuthenticationContext in ProductSidebarone and useEffect on loggedIn from the context to setOpenPricing(true).

I hope this clarifies it.

EDIT:

I will try to provide a minimal example, including the missing provider. Note that this is not tested.

import React, { createContext } from 'react';

// Create and export context
export const AuthenticationContext = createContext({
  loggedIn: false,
  setLoggedIn: () => {},
});
//e.g. App.js
import { AuthenticationContext } from 'PATH';

const App = () => {
   ...
   // Hold state for context
   const [loggedIn, setLoggedIn] = useState(false);

   return (
      ...
      // Provide context to child components in app
      <AuthenticationContext.Provider value={{loggedIn, setLoggedIn}}>
         ...
      </AuthenticationContext.Provider>
   )
}
import React, { useState, useContext, useEffect } from 'react';
import { Link } from 'react-router-dom';
import Modal from 'react-modal';

import { AuthenticationContext } from '../../../others/common/context';

function ProductSidebarOne(props) {
  const [openPricing, setOpenPricing] = useState(false);

  // Connect to context
  const { loggedIn } = useContext(AuthenticationContext);

  // Here we can use the state inside context
  // e.g. react to change in context
  useEffect(() => {
     if(loggedIn) setOpenPricing(true)
  }, [loggedIn])

  return (...)
}
import React, { useState, useContext } from 'react';
import axios from 'axios';

import { setUserSession } from '../../../../utils';
import { AuthenticationContext } from '../common/context';

function Login(props) {
  ...

  const { loggedIn, setLoggedIn } = useContext(AuthenticationContext);

  const handleLogin = (e) => {
    e.preventDefault();

    axios.post("api url", {
      email: email,
      password: password
    })
    .then(response => {
      setUserSession(response.data);
      // Manipulate state from any child
      setLoggedIn(true);
      props.history.push(props.location.state.from);
    });
  }

  return (...)
}

export default Login;
prohit
  • 609
  • 1
  • 6
  • 18
  • I have tried this solution and it doesn't work or i am doing something wrong. The problem is probably that the components are not connected by the provider and I have no way of getting them connected. I will put the code below. – andrzej Dec 23 '21 at 14:09
  • Yes, you have to wrap components that will use the context (probably your whole application?) with a provider. This provider ultimately holds the state for authentication which will trigger rerendering on all connected components. – prohit Dec 24 '21 at 13:19
  • I edited the answer with an example including a provider. Please see if that helps. – prohit Dec 24 '21 at 13:42