- Notifications
You must be signed in to change notification settings - Fork 300
Open
Description
I have working code to make the render prop expression as a child component.
Please let me know if this transformer code would be useful to add to the react-codemod code base.
My use case was that the Formik library is deprecating the use of render prop in their API.
https://formik.org/docs/api/formik#render-props-formikpropsvalues--reactnode
https://astexplorer.net/#/gist/d3df017f80a840c55c4f7041154c0a0d/8a482bb109f7c5e34fc8ab43296f797991d1989b
Downloadable file: https://gist.github.com/d3df017f80a840c55c4f7041154c0a0d/8a482bb109f7c5e34fc8ab43296f797991d1989b
Here is the transformer code:
const isRenderProp = (object) => { return object.name && object.name.name == "render"; }; const hasRenderProp = (path) => { return path && path.value && path.value.openingElement && path.value.openingElement.attributes.filter(isRenderProp).length > 0; }; const update = (api) => (path) => { const renderProp = path.value.openingElement.attributes.filter(isRenderProp)[0]; // remove render prop path.value.openingElement.attributes = path.value.openingElement.attributes.filter((path) => !isRenderProp(path)); // make field a non closing field path.value.openingElement.selfClosing = false; path.value.closingElement = api.jscodeshift.jsxClosingElement(path.value.openingElement.name); // make element in render prop now a child of the react element if (renderProp && renderProp.value && renderProp.value.expression) { path.value.children.push(renderProp.value); } return path; }; export default function transformer(file, api) { const j = api.jscodeshift; const root = j(file.source); root .find(j.JSXElement, { closingElement: null }) .filter(hasRenderProp) .forEach(update(api)); return root.toSource(); }
Example Input:
const App = () => { <FieldArray name={orderLinesFieldName} render={(arrayHelpers) => { const priceFieldName = `${orderLinesFieldName}[${i}].${priceFieldConst}`; return ( <Field name={priceFieldName} render={({ form, field }) => { const error = getIn(form.errors, field.name); return ( <CenteredCell> <Block>USD</Block> <Input {...(error ? { error: true } : {})} type="number" overrides={{ Input: { props: { "data-testid": "existing-adjustment-amount", }, }, }} disabled={actionItemStatus === statusClosed} value={orderLines[i].price} onChange={(e) => { arrayHelpers.replace(i, { ...orderLines[i], price: e.target.value, }); }} /> </CenteredCell> ); }} /> );
Example output
const App = () => { <FieldArray name={orderLinesFieldName}>{(arrayHelpers) => { const priceFieldName = `${orderLinesFieldName}[${i}].${priceFieldConst}`; return ( (<Field name={priceFieldName}>{({ form, field }) => { const error = getIn(form.errors, field.name); return ( <CenteredCell> <Block>USD</Block> <Input {...(error ? { error: true } : {})} type="number" overrides={{ Input: { props: { "data-testid": "existing-adjustment-amount", }, }, }} disabled={actionItemStatus === statusClosed} value={orderLines[i].price} onChange={(e) => { arrayHelpers.replace(i, { ...orderLines[i], price: e.target.value, }); }} /> </CenteredCell> ); }}</Field>) ); }}</FieldArray>; };
More about render props here: https://reactjs.org/docs/render-props.html
Metadata
Metadata
Assignees
Labels
No labels