Skip to content

Instantly share code, notes, and snippets.

@SebastianHGonzalez
Last active August 1, 2019 14:56
Show Gist options
  • Save SebastianHGonzalez/18bd41dc11488b7cef78f9e5d4c967a9 to your computer and use it in GitHub Desktop.
Save SebastianHGonzalez/18bd41dc11488b7cef78f9e5d4c967a9 to your computer and use it in GitHub Desktop.
import React, { useState, useCallback } from "react";
import { func } from "prop-types";
import { connect } from "react-redux";
import useHistory from "./useHistory";
import FirstStep from "./FirstStep";
import SecondStep from "./SecondStep";
import ThirdStep from "./ThirdStep";
import FlowTransition from "./FlowTransition";
const steps = {
first: "first",
second: "second",
third: "third",
// ...
};
export function FlowExample({ onSubmit, onCancel }) {
const [backwards, setBackwards] = useState(false);
const [currentStep, setStep, goBack] = useHistory([steps.first]);
// https://reactjs.org/docs/hooks-reference.html#usestate
const [firstStepData, setFirstStepData] = useState({});
const [secondStepData, setSecondStepData] = useState({});
const [thirdStepData, setThirdStepData] = useState({});
const handleThirdStepSubmit = useCallback(
(newThirdStepData) => {
setBackwards(false);
onSubmit({
// Change to suit your needs
...firstStepData,
...secondStepData,
...newThirdStepData,
});
},
[onSubmit, firstStepData, secondStepData],
);
const handleThirdStepCancel = useCallback(
(newThirdStepData) => {
setBackwards(true);
setThirdStepData(newThirdStepData);
goBack();
},
[goBack, setSecondStepData],
);
const handleSecondStepSubmit = useCallback(
(newSecondStepData) => {
setBackwards(false);
setSecondStepData(newSecondStepData);
setStep(steps.third);
},
[setStep, setSecondStepData],
);
const handleSecondStepCancel = useCallback(
(newFirstStepData) => {
setBackwards(true);
setSecondStepData(newFirstStepData);
goBack();
},
[goBack, setSecondStepData],
);
const handleFirstStepSubmit = useCallback(
(newFirstStepData) => {
setBackwards(false);
setFirstStepData(newFirstStepData);
setStep(steps.second);
},
[setStep, setFirstStepData],
);
const handleFirstStepCancel = useCallback(
(newFirstStepData) => {
setBackwards(true);
onCancel({
// Change to suit your needs
...newFirstStepData,
...secondStepData,
...thirdStepData,
});
},
[onCancel, secondStepData, thirdStepData],
);
return (
<FlowTransition
backwards={backwards}
currentPage={currentStep}
pages={{
[steps.first]: () => (
<FirstStep
initialValues={firstStepData}
onSubmit={handleFirstStepSubmit}
onCancel={handleFirstStepCancel}
/>
),
[steps.second]: () => (
<SecondStep
name={firstStepData.name}
initialValues={secondStepData}
onSubmit={handleSecondStepSubmit}
onCancel={handleSecondStepCancel}
/>
),
[steps.third]: () => (
<ThirdStep
initialValues={thirdStepData}
onSubmit={handleThirdStepSubmit}
onCancel={handleThirdStepCancel}
/>
),
}}
/>
);
}
export default connect(
null, // mapStateToProps
(dispatch) => ({
// mapDispatchToProps
onSubmit: (values) => {
// Change to suit your needs
debugger;
},
onCancel: () => {
// Change to suit your needs
// dispatch(rouoterActions.goBack()) // is usually a good choice
debugger;
},
}),
)(FlowExample);
FlowExample.propTypes = {
onSubmit: func,
onCancel: func,
};
FlowExample.defaultProps = {
onSubmit: noop,
onCancel: noop,
};
function noop() {}
import React from "react";
import { string, number, bool, node, element, oneOf, arrayOf } from "prop-types";
import { useTransition, animated } from "react-spring";
import styled from "styled-components";
export default function FlowTransition({ pages, currentPage, backwards, wrapper: TransitionWrapper }) {
const transitions = useTransition(currentPage, (p) => p, {
from: {
position: "absolute",
opacity: 0,
transform: backwards ? "translate3d(-100%,0,0)" : "translate3d(100%,0, 0)",
},
enter: { position: "unset", opacity: 1, transform: "translate3d(0, 0, 0)" },
leave: {
position: "absolute",
opacity: 0,
transform: backwards ? "translate3d(50%,0,0)" : "translate3d(-50%,0, 0)",
},
});
return (
<TransitionWrapper>
{transitions.map(({ item, props, key }) => {
const Page = pages[item];
return (
<animated.div key={key} style={props}>
<Page />
</animated.div>
);
})}
</TransitionWrapper>
);
}
const StyledTransitionWrapper = styled.div`
will-change: transform, opacity;
`;
FlowTransition.propTypes = {
pages: oneOf([node, arrayOf(node)]),
currentPage: oneOf([number, string]),
backwards: bool,
wrapper: element,
};
FlowTransition.defaultProps = {
pages: [],
currentPage: 0,
backwards: false,
wrapper: StyledTransitionWrapper,
};
import { useState, useCallback } from "react";
export default function useHistory(initialHistory) {
const [history, setHistory] = useState(initialHistory || []);
const [value, ...previousValues] = history;
const undo = useCallback(() => {
// useCallback is used for performance reasons
// https://reactjs.org/docs/hooks-reference.html#usecallback
setHistory(previousValues);
}, [history, setHistory]);
const setValue = useCallback(
(newValue) => {
setHistory([newValue, ...history]);
},
[history, setHistory],
);
return [value, setValue, undo, previousValues];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment