Skip to content

Commit

Permalink
fix(class-to-functional): useState calls not generated if no default …
Browse files Browse the repository at this point in the history
…is set
  • Loading branch information
Boris Litvinsky committed Oct 31, 2019
1 parent 542a6e4 commit d2de1cd
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 14 deletions.
19 changes: 12 additions & 7 deletions src/modules/stateful-to-stateless.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export function statefulToStateless(component) {
t.isFunctionExpression(path.node.arguments[0]) ||
t.isArrowFunctionExpression(path.node.arguments[0])
) {
handleFunctionalStateUpdate(path, buildRequire);
handleFunctionalStateUpdate(path, buildRequire, stateProperties);
} else {
path.node.arguments[0].properties.forEach(({ key, value }) => {
path.insertBefore(
Expand All @@ -100,6 +100,10 @@ export function statefulToStateless(component) {
STATE_VALUE: value
})
);

if (!stateProperties.has(key.name)) {
stateProperties.set(key.name, void 0);
}
});
}

Expand All @@ -119,8 +123,7 @@ export function statefulToStateless(component) {
}
};

let stateHooksPresent,
nonLifeycleMethodsPresent = false;
let nonLifeycleMethodsPresent = false;

let effectBody, effectTeardown;

Expand Down Expand Up @@ -269,7 +272,6 @@ export function statefulToStateless(component) {
}) || {};

if (expression && expression.left.property.name === "state") {
stateHooksPresent = true;
expression.right.properties.map(({ key, value }) => {
stateProperties.set(key.name, value);
});
Expand All @@ -288,7 +290,6 @@ export function statefulToStateless(component) {
copyNonLifeCycleMethods(path);
}
if (t.isObjectExpression(propValue) && path.node.key.name === "state") {
stateHooksPresent = true;
(propValue.properties as t.ObjectProperty[]).map(({ key, value }) => {
stateProperties.set(key.name, value);
});
Expand Down Expand Up @@ -356,12 +357,12 @@ export function statefulToStateless(component) {
return {
text: processedJSX,
metadata: {
stateHooksPresent,
stateHooksPresent: stateProperties.size > 0,
nonLifeycleMethodsPresent
}
};
}
function handleFunctionalStateUpdate(path: any, buildRequire: any) {
function handleFunctionalStateUpdate(path: any, buildRequire: any, stateProperties) {
const stateProducer = path.node.arguments[0];
const stateProducerArg = stateProducer.params[0];
const isPrevStateDestructured = t.isObjectPattern(stateProducerArg);
Expand Down Expand Up @@ -414,6 +415,10 @@ function handleFunctionalStateUpdate(path: any, buildRequire: any) {
STATE_VALUE: fn
})
);

if (!stateProperties.has(prop.key.name)) {
stateProperties.set(prop.key.name, void 0);
}
});
}

Expand Down
17 changes: 10 additions & 7 deletions src/test/class-to-functional.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe("when refactoring stateful component into stateless component", () => {
jsModuleSystem: "esm",
jsFilesExtensions: ["js"],
switchToTarget: true,
showConversionWarning: true,
showConversionWarning: true
});
sandbox.stub(fileSystem, "appendTextToFile").returns(Promise.resolve());

Expand All @@ -64,16 +64,16 @@ describe("when refactoring stateful component into stateless component", () => {
"No"
]);
});

it("does not show warning dialog when it is disabled", async () => {
givenDeclinedWarning();

configStub.restore();
sandbox.stub(editor, "config").returns({
jsModuleSystem: "esm",
jsFilesExtensions: ["js"],
switchToTarget: true,
showConversionWarning: false,
showConversionWarning: false
});

await statefulToStatelessComponent();
Expand Down Expand Up @@ -290,7 +290,8 @@ describe("when refactoring stateful component into stateless component", () => {
await statefulToStatelessComponent();

expect(fileSystem.replaceTextInFile).to.have.been.calledWith(
"const SomeComponent = props => {\n const someMethod = useCallback(() => {\n setFoo(prevFoo => {\n return prevFoo;\n });\n });\n return <div />;\n};", selectedTextStart,
"const SomeComponent = props => {\n const [foo, setFoo] = useState();\n const someMethod = useCallback(() => {\n setFoo(prevFoo => {\n return prevFoo;\n });\n });\n return <div />;\n};",
selectedTextStart,
selectedTextEnd,
"/source.js"
);
Expand All @@ -316,7 +317,8 @@ describe("when refactoring stateful component into stateless component", () => {
await statefulToStatelessComponent();

expect(fileSystem.replaceTextInFile).to.have.been.calledWith(
"const SomeComponent = props => {\n const someMethod = useCallback(() => {\n setFoo(prevFoo => {\n return prevFoo;\n });\n setBar(prevBar => {\n return prevBar;\n });\n });\n return <div />;\n};", selectedTextStart,
"const SomeComponent = props => {\n const [foo, setFoo] = useState();\n const [bar, setBar] = useState();\n const someMethod = useCallback(() => {\n setFoo(prevFoo => {\n return prevFoo;\n });\n setBar(prevBar => {\n return prevBar;\n });\n });\n return <div />;\n};",
selectedTextStart,
selectedTextEnd,
"/source.js"
);
Expand All @@ -342,7 +344,8 @@ describe("when refactoring stateful component into stateless component", () => {
await statefulToStatelessComponent();

expect(fileSystem.replaceTextInFile).to.have.been.calledWith(
"const SomeComponent = props => {\n const someMethod = useCallback(() => {\n setFoo(prevFoo => {\n return prevFoo;\n });\n setBar(prevBar => {\n return prevBar;\n });\n });\n return <div />;\n};", selectedTextStart,
"const SomeComponent = props => {\n const [foo, setFoo] = useState();\n const [bar, setBar] = useState();\n const someMethod = useCallback(() => {\n setFoo(prevFoo => {\n return prevFoo;\n });\n setBar(prevBar => {\n return prevBar;\n });\n });\n return <div />;\n};",
selectedTextStart,
selectedTextEnd,
"/source.js"
);
Expand Down

0 comments on commit d2de1cd

Please sign in to comment.