How can I fix eslint: react/destructuring-assignment error? - javascript

const Container = (props) => {
return (
<StyledDiv>
<SmallScreenDiv>{props.children}</SmallScreenDiv>
</StyledDiv>
);
};
This is my code and error happens at {props.children}
how can I fix this eslint error?

There are two solution for this
Disable the prefer-destructuring feature on the eslint
destructure your props
const Container = ({children}) => {
return (
<StyledDiv>
<SmallScreenDiv>{children}</SmallScreenDiv>
</StyledDiv>
);
};
or
const Container = (props) => {
const {children} = props
return (
<StyledDiv>
<SmallScreenDiv>{children}</SmallScreenDiv>
</StyledDiv>
);
};
I will recommend to use second option.

You can also destruct your props like this:
const Container = ({children}) => {
return (
<StyledDiv>
<SmallScreenDiv>{children}</SmallScreenDiv>
</StyledDiv>
);
};

Related

How to return a component in an async method within a FlatList

I have a functional component
const Foo = () => {
const _renderSomething = async id => {
const data = await database.get(SOME_TABLE).Where(someColumnValue = id);
return Promise.resolve(
<AnotherComponent
data={data} />
);
};
const _renderCard = ({item}) => {
const {code, id} = item;
...
return (
<Card
index={code}>
{_renderSomething(id)}
</Card>
);
};
return (
<FlatList
data={rawData}
initialNumToRender={rawData.length}
keyExtractor={item => item.code}
renderItem={_renderCard}
/>
);
Now, this gives me
ERROR Error: Objects are not valid as a React child (found: object with keys {_U, _V, _W, _X}). If you meant to render a collection of children, use an array instead.
Which I do not quite understand.
First, I notice that there is a syntax error in renderCard. This is not valid JSX since the ending tag doesn't match the opening tag and props should be passed into the component like propName={propValue}.
<Card
index={code}
{_renderSomething(id)}
</FlipCard>
I assume that maybe you intended to write this
<Card index={code}>
{_renderSomething(id)}
</Card>
Where you are passing the result of _renderSomething as the Card component's children prop. Which explains that error that you get as async functions are not valid as React child element.
Instead you can refactor _renderSomething into a separate React component and do the data loading within a useEffect hook.
const Something = ({ id }) => {
const [data, setData] = useState(null);
useEffect(() => {
database.get(...).then(setData);
}, [id])
return (
<AnotherComponent data={data} />
);
};
This can then be used within _renderCard like so
const _renderCard = ({item}) => {
const {code, id} = item;
...
return (
<Card index={code}>
<Something id={id} />
</Card>
);
};

How to appendChild custom component using React JS and Typescript?

I have some code like
const ParentComponent = () => {
let child = <ChildComponent {...props} />;
if (condition) {
const parent = document.GetElementById("parentId");
//Here is a problem
parent.appendChild(child);
}
return (
<>
<div id="parentId"></div>
</>
);
};
export default ParentComponent;
const ChildComponent = () => {
return (
<>
<div></div>
</>
);
};
export default ChildComponent;
I want to dynamically add child components multiple times but getting an error
I am happy to do it in any way using Javascript or useRef.
Thanks!
The standard way to do conditional rendering in react is as follows:
const ParentComponent = () => {
return (
<>
<div id="parentId">
{condition && <ChildComponent {...props } />}
</div>
</>
);
};
export default ParentComponent;
You mentioned wanting to do it multiple times, though you didn't show an example of what you have in mind. You can create an array and fill it with however many child elements you want. For example:
const ParentComponent = () => {
const [childCount, setChildCount] = useState(8);
const children = [];
for (let i = 0; i < childCount; i++) {
if (condition) {
children.push(<ChildComponent {...props } />);
}
}
return (
<>
<div id="parentId">
{children}
</div>
</>
)
}

Stripe ElementsConsumer with TypeScript: Pass prop?

I'm using TypeScript 3.8 with ReactJs, using class-style components, and I'm following an example here: https://stripe.com/docs/stripe-js/react
In these docs, they show the use of the ElementsConsumer as such:
const InjectedCheckoutForm = () => {
return (
<ElementsConsumer>
{({elements, stripe}) => (
<CheckoutForm elements={elements} stripe={stripe} />
)}
</ElementsConsumer>
);
};
This works fine. But I'd like to pass my own prop into the inner like :
<InjectedCheckoutForm backgroundColor={"Green"} />
Does anyone have any suggestions on how to achieve this? I can't tell if I should add a parameter here:
const InjectedCheckoutForm = (backgroundColor: string) => {
return (
....???
Also, does this qualify as a "high order component?" I haven't seen this style of wrapping a component before. The closest thing I've seen is the Redux 'connect' function.
import React, { FC } from 'react';
interface TestInterface {
backgroundColor: string
}
const InjectedCheckoutForm: FC<TestInterface> = props => {
...
const x = props.backgroundColor;
...
return (
<View style={{ 'backgroundColor': x }}>Hello boy<View>
)
}
OR SIMPLE
const InjectedCheckoutForm = ({backgroundColor}) => {
...
const x = backgroundColor
...
}
It took writing this out for me to figure it out. I'm less experienced with functional components, but the key was moving from
const InjectedCheckoutForm = () => {
return (
<ElementsConsumer>
{({ elements, stripe }) => (
<CreditCardForm backgroundColor={???} elements={elements} stripe={stripe} />
)}
</ElementsConsumer>
);
};
to
const InjectedCheckoutForm = (props) => {
return (
<ElementsConsumer>
{({ elements, stripe }) => (
<CreditCardForm backgroundColor={props.backgroundColor} elements={elements} stripe={stripe} />
)}
</ElementsConsumer>
);
};
(Props are wrapped in a single 'props' parameter.)
I hope this is helpful to others who may have had the same question.

React hook callback from child to parent

I have this child component called TodoList
const TodoItem = ({ checked, children }) =>
(<TouchableOpacity
style={{ backgroundColor: checked && 'red'}}>
{children}
</TouchableOpacity>
);
const TodoList = props => {
const {
options = [],
onSelect,
...rest
} = props;
const [selectedOptionIndex, setSelectedOptionIndex] = useState(null);
useEffect(() => {
onSelect(options[selectedOptionIndex]);
}, [onSelect, options, selectedOptionIndex]);
const renderItem = (o, index) => {
return (
<TodoItem
key={o + index}
onPress={() => setSelectedOptionIndex(index)}
checked={index === selectedOptionIndex}>
{index === selectedOptionIndex && <Tick />}
<Text>{o}</Text>
</TodoItem>
);
};
return (
<View {...rest}>{options.map(renderItem)}</View>
);
};
export default TodoList;
And I have a parent component called Container
export default function() {
const [item, setItem] = setState(null);
return (
<Screen>
<TodoList options={[1,2,3]} onSelect={(i) => setItem(i)} />
</Screen>
)
}
I want to have a callback from child component to parent component using onSelect whenever a TodoItem is selected. However, whenever the onSelect is called, my TodoList re-renders and my selectedOptionIndex is reset. Hence, my checked flag will only change to true briefly before resetting to false.
If I remove the onSelect callback, it works fine. But I need to setState for both child and parent. How do I do that?
It's hard to tell why thats happening for you, most likely because the container's state is changing, causing everything to rerender.
Something like this should help you out, though.
const { render } = ReactDOM;
const { useEffect, useState } = React;
const ToDoItem = ({checked, label, onChange, style}) => {
const handleChange = event => onChange(event);
return (
<div style={style}>
<input type="checkbox" checked={checked} onChange={handleChange}/>
{label}
</div>
);
}
const ToDoList = ({items, onChosen}) => {
const [selected, setSelected] = useState([]);
const handleChange = item => event => {
let s = [...selected];
s.includes(item) ? s.splice(s.indexOf(item), 1) : s.push(item);
setSelected(s);
onChosen(s);
}
return (
<div>
{items && items.map(i => {
let s = selected.includes(i);
return (
<ToDoItem
key={i}
label={i}
onChange={handleChange(i)}
checked={s}
style={{textDecoration: s ? 'line-through' : ''}}/>
)
})}
</div>
);
}
const App = () => {
const [chosen, setChosen] = useState();
const handleChosen = choices => {
setChosen(choices);
}
return (
<div>
<ToDoList items={["Rock", "Paper", "Scissors"]} onChosen={handleChosen} />
{chosen && chosen.length > 0 && <pre>Chosen: {JSON.stringify(chosen,null,2)}</pre>}
</div>
);
}
render(<App />, document.body)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
Turned out my top-level component Screen is causing this re-render. In my Screen functional component, I have this piece of code before the return
const Content = scroll
? contentProps => {
const { style: contentContainerStyle } = contentProps;
return (
<ScrollView {...contentContainerStyle}>
{contentProps.children}
</ScrollView>
);
}
: View;
return (
<Content>{children}</Content>
)
And it somehow (not sure why) causes the children to re-render every time my state changes.
I fixed it by removing the function and have it simply returning a View
const Content = scroll ? ScrollView : View;

How can I prevent compound component from re-rendering?

I am using react context, and all it contains at the moment are 3 items: contacts and editingContact, and editContact:
interface ContactsContextProps {
contacts: Contact[];
editingContact: Contact;
editContact: (contact: Contact) => () => void // being lazy and this is from an onClick
}
const ContactsContext = React.createContext<Partial<ContactsContextProps>>({
editContact: (contact: Contact) => () => {}
})
const ContactsProvider: React.FunctionComponent = props => {
const [contacts, setContacts] = useState<Contact[]>();
const [editingContact, setEditingContact] = useState<Contact>();
React.useEffect(() => {
// fetch contacts, and setContacts(contacts)
}, [])
const editContact = React.useCallback((contact: Contact) => {
return function() {
setEditingContact(contact);
}
})
return (
<ContactsContext.Provider
value={{
editingContact,
editContact,
contacts
}}
>
{props.children}
</ContactsContext.Provider>
)
}
Here's how it is being used:
const ContactsList: React.FunctionComponent<{
contacts: Contact[];
}> = React.memo(props => {
return (
<>
{props.contacts.map(contact => (
<Card key={contact.id} contact={contact} />
))}
</>
);
});
const Wrapper: React.FunctionComponent = () => {
const contactsCtx = React.useContext(ContactsContext);
return (
<>
<Box className={styles.main}>
<Header />
{contactsCtx.contacts && <ContactsList contacts={contactsCtx.contacts} />}
</Box>
{contactsCtx.editingContact && <EditContactModal />}
</>
);
};
The <Card /> only has an edit button right now, which calls contactsContext.editContact(). However, each time this is called, all the Cards re-render. I placed a console.log('card') in each Card, and it logs card 10 times (I have 10 contacts right now).
What am I doing wrong?
There has been a discussion in a React Github issue, basically there is 3 possible solutions for this:
Option 1 (Preferred): Split contexts that don't change together
Option 2: Split your component in two, put memo in between
Option 3: One component with useMemo inside
You should check the link for examples about it.

Categories