supasate / connected-react-router

A Redux binding for React Router v4
MIT License
4.73k stars 593 forks source link

Push not working #475

Open tonybrbtravel opened 3 years ago

tonybrbtravel commented 3 years ago

The app is wired up such that: -> user lands on Sign-up page -> call is made to action, picked up by the sign-up saga. -> The push is never made.

I'm sure I've wired something up incorrectly, but have spent a day looking at it.

Your help is appreciated.

index.js


import React from 'react';
import ReactDOM from 'react-dom';
import { ConnectedRouter } from 'connected-react-router'
import './index.css';
import App from './App';
import store, {history} from './app/store';
import { Provider } from 'react-redux';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
<Provider store={store}>
        <ConnectedRouter history={history}>
            <App />
        </ConnectedRouter>
    </Provider>
  document.getElementById('root')
);

app/store.js

import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { createBrowserHistory } from 'history'
import createSagaMiddleware from "redux-saga";
import createRootReducer from './reducers'
import rootSaga from './saga'

export const history = createBrowserHistory();

let sagaMiddleware = createSagaMiddleware();
const middleware = [...getDefaultMiddleware({ thunk: false }), sagaMiddleware];

export default configureStore({
  reducer: createRootReducer(history),
  middleware
});

sagaMiddleware.run(rootSaga);

App.js

import React from 'react';
import logo from './logo.svg';
import { Counter } from './features/counter/Counter';
import { SignUp } from './features/sign-up/Signup';
import './App.css';
import Amplify, { Auth } from 'aws-amplify';

import routes from './routes'

function App() {
  return (
    <div className="App">
        { routes }
    </div>
  );
}

export default App;

routes.js

import React from 'react'
import { Route, Switch } from 'react-router-dom'
import {SignUp} from '../features/sign-up/Signup'
import {VerifySignUp} from '../features/verify-signup/VerifySignUp'

const routes = (
    <Switch>
      <Route exact path="/" component={SignUp} />
      <Route exact path="/verify-sign-up" component={VerifySignUp} />
    </Switch>
)

export default routes
sign-ip\saga.js

import {
  take,
  call,
  all,
  put,
  cancel,
  select,
  takeLatest,
} from 'redux-saga/effects';

import { push } from 'connected-react-router';
import store, {history} from '../../app/store';

import { Auth } from 'aws-amplify';

import {signUpFormUpdate, selectSignUpForm, signUpErrorUpdate} from './signupSlice';

export function* signUp() {
  try {
  const signUpForm = yield select(selectSignUpForm());

  const result = yield call([Auth, Auth.signUp], {
        username: signUpForm.email,
        password: signUpForm.password,
        attributes: {
          ...(signUpForm.preferred_name && {
            preferred_username: signUpForm.preferred_name,
          }),
          email: signUpForm.email,
        },
        validationData: [],
      });
  yield put(push('/verify-sign-up'));
  } catch (err) {
    console.log(err);
    yield put(signUpErrorUpdate(err));
  }
}

export function* signUpwatcher() {
  yield takeLatest(signUpFormUpdate().type, signUp)
}

Singup.js

import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import styled from 'styled-components';

import { Link } from 'react-router-dom';

import {H1} from '../../components/H1';
import {Input} from '../../components/Input';
import {Spacer} from '../../components/Spacer';
import {SubmitButton} from '../../components/SubmitButton';
import {Checkbox} from '../../components/Checkbox';
import Colors from '../../themes/Colors';
import Metrics from '../../themes/Metrics';
import { fadeIn } from '../../themes/animations';

import {signUpFormUpdate} from './signupSlice';

import { push } from 'connected-react-router';
import {history} from '../../app/store';

const Form = styled.form`
`;

const FlexWrapper = styled.div`
  display: flex;
  flex-direction: column;
  min-height: 100vh;

  @media screen and (min-width: 720px) {
    flex-direction: row;
    height: 100vh;
  }
`;

const SubTextc = styled.ul`
  text-align: left;
  font-size: 14px;
  margin: 0;
  padding: 0;
  opacity: 0.8;
  list-style-type: none;
  margin: 0;
  padding: 0;

  li {
      display: inline-block;
      margin-right: 20px;
    }

  @media screen and (min-width: 720px) {
    font-size: 16px;
  }
`;
const H1c = styled(H1)`
  text-align: left;
  padding: 0;
  font-size: 24px;
  letter-spacing: -0.86px;
  margin-bottom: 16px;

  @media screen and (min-width: 640px) {
    font-size: 32px;
  }
`;

const ErrorBox = styled.div`
  max-width: 860px;
  padding: 12px;
  border-radius: 6px;
  background-color: white;
  box-shadow: 0px 2px 12px ${Colors.lightShadow};
  margin: 0 auto 12px auto;
  animation: ${fadeIn} 0.5s ease-in-out backwards;

  strong {
    color: ${Colors.red};
  }
`;

const FormWrapper = styled.div`
  padding: 30px 20px 0px 20px;
  width: 100%;

  @media screen and (min-width: 600px) {
    padding: 30px 60px;
    max-width: 800px;
  }
`;

const LeftPanel = styled.div`
  height: 100%;
  width: 100%;

  @media screen and (min-width: 720px) {
    width: 50%;
    max-width: 480px;
  }
`;

const RightPanel = styled.div`
  display: flex;
  flex-grow: 1;
  overflow: hidden;
  overflow-y: scroll;
  align-items: center;
`;

const LinkS = styled(Link)`
  color: ${Colors.blue};
`;

const Label = styled.label`
  display: flex;
  align-items: center;
  font-size: 14px;
  color: #909090;
  margin-bottom: 30px;

  a {
    color: ${Colors.red};
  }
`;

export const SignUp = () => {
  const dispatch = useDispatch();
  const signUpForm = useSelector(state => state.signup.signUpForm)
  const error = useSelector(state => state.signup.signUpError)
  let[checked, updateChecked] = useState(false)
  const[form, updateForm] = useState(null)

  const onChange = (type, evt) => {
    const newForm = Object.assign({}, form)
    newForm[type] = evt.target.value
    updateForm(newForm)
  }

  const handleCheckboxChange = () => {
    checked == false ? checked = true : checked = false
  }

  const onSubmit = (evt) => {
    evt.preventDefault();
    dispatch(signUpFormUpdate(form))
  }

  let PreferredName = <Input
       name="preferredName"
       placeholder="First name / Nickname"
       value={form ? form.preferredName : ''}
       onChange={(evt) => onChange('preferredName', evt)}
       error={
         error && error.preferred_name ? error.preferred_name : null
       }
       blue
   />

  let Email = <Input
      name="email"
      placeholder="Email"
      type="email"
      value={form ? form.email : ''}
      onChange={(evt) => onChange('email', evt)}
      error={error && error.email ? error.email : null}
      blue
  />

  let Password = <Input
      name="password"
      placeholder="Password"
      type="password"
      value={form ? form.password : ''}
      onChange={(evt) => onChange('password', evt)}
      error={error && error.password ? error.password : null}
        blue
      />

    let GoButton = <SubmitButton value="Create your free account" blue />

    let TandC = <Label>
        <Checkbox
          checked={checked}
          onChange={handleCheckboxChange}
        />
        <span>I have read and accept the <Link to="/terms-and-conditions" target="_blank">terms and conditions</Link> and <Link to="/privacy-policy" target="_blank">privacy policy</Link></span>
    </Label>

  return (
    <FlexWrapper>
      <LeftPanel>
      </LeftPanel>
      <RightPanel>
        <FormWrapper>
          <H1c>Sign up to build your profile</H1c>
          <SubTextc>
            <li>✓ Build your bucketlist</li>
            <li>✓ Select your airports</li>
            <li>✓ Choose your plan</li>
          </SubTextc>
          <Spacer height={Metrics.smallSpacer} />
          <Form onSubmit={onSubmit}>
            {PreferredName}
            {Email}
            {Password}
            {TandC}
            {GoButton}
            {error && error && (
              <ErrorBox>
                <strong>Error:</strong> {error.message || error}
              </ErrorBox>
             )}
             <Spacer height={Metrics.tinySpacer} />
             <p
              style={{
                margin: '20px 0',
                fontSize: '18px',
                textAlign: 'center',
              }}
             >
                Already have an account? <LinkS to="/sign-in">Sign in</LinkS>
            </p>
          </Form>
        </FormWrapper>
      </RightPanel>
    </FlexWrapper>
  );
}
Narven commented 3 years ago

@tonybrbtravel There is no point on adding these kind of issues here about push. It does not work, and never worked and probably never will. There are hundreds of complains about the same thing all the way back to 2017.

Is quite sad that all of these libraries that do amazing, awesome things, and cannot do the most basic functionality of the internet... redirecting from one url to another. It's quite impressive... or sad.

lightyisu commented 3 years ago

@tonybrbtravel There is no point on adding these kind of issues here about push. It does not work, and never worked and probably never will. There are hundreds of complains about the same thing all the way back to 2017.

Is quite sad that all of these libraries that do amazing, awesome things, and cannot do the most basic functionality of the internet... redirecting from one url to another. It's quite impressive... or sad.

eh…but why it doesnt work and how to solve it

joegasewicz commented 3 years ago

@Narven @lightyisu This works. You just have to make sure that you do not create your middleware and pass in the history api before calling createRootReducer function. If you try to create your middleware with routerMiddleware(history) too early , history will be passed in as undefined. Follow the README.md as it explains the exact execution order.

lightyisu commented 3 years ago

@Narven @lightyisu This works. You just have to make sure that you do not create your middleware and pass in the history api before calling createRootReducer function. If you try to create your middleware with routerMiddleware(history) too early , history will be passed in as undefined. Follow the README.md as it explains the exact execution order.

Thank u so much for ur help,I will try it😘

tonybrbtravel commented 3 years ago

After many hours, I have this working.

import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { createBrowserHistory } from 'history'
import createSagaMiddleware from "redux-saga";
import { routerMiddleware } from 'connected-react-router'
import { applyMiddleware, compose } from 'redux'

import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' // defaults to localStorage for web

import createRootReducer from './reducers'
import rootSaga from './saga'

export const history = createBrowserHistory();

const persistConfig = {
  key: 'root',
  storage,
}

const rootReducer = createRootReducer(history);
const persistedReducer = persistReducer(persistConfig, rootReducer)

let sagaMiddleware = createSagaMiddleware();
const middleware = [...getDefaultMiddleware({ thunk: false }), sagaMiddleware, routerMiddleware(history)];

export default configureStore({
  reducer: persistedReducer,
  middleware
});

sagaMiddleware.run(rootSaga);
import React from 'react';
import ReactDOM from 'react-dom';
import { PersistGate } from 'redux-persist/integration/react'
import { persistStore, persistReducer } from 'redux-persist'
import { ConnectedRouter } from 'connected-react-router'
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";
import './index.css';
import App from './App';
import store, {history} from './app/store';
import { Provider } from 'react-redux';
import * as serviceWorker from './serviceWorker';

let persistor = persistStore(store)

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
        <PersistGate loading={null} persistor={persistor}>
            <ConnectedRouter history={history}>
                <App />
            </ConnectedRouter>
        </PersistGate>
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import {SignUp} from '../features/sign-up/Signup'
import {SocialSignUp} from '../features/social-sign-up/SocialSignUp'
import {Dashboard} from '../features/dashboard/Dashboard'
import TermsAndConditions from '../features/t-and-c/Terms.js'

const routes = (
    <Switch>
      <Route exact path="/" component={Dashboard} />
      <Route exact path="/email-signup" component={SignUp} />
      <Route exact path="/social-signup" component={SocialSignUp} />
      <Route exact path="/terms-and-conditions" component={TermsAndConditions} />
    </Switch>
)

export default routes
ee0pdt commented 3 years ago

@Narven We've been using the lib in a production app for over 2 years, I can tell you that push definitely works!