React don't render mapping elements - javascript

I'm mapping Array and React don't want to render this.
Typescript gives this error: "This JSX tag's 'children' prop expects a single child of type 'ReactNode', but multiple children were provided.".
But when I use React fragment in component instead of div error isn't detected.
Why React don't render?
import { useDispatch, useSelector } from 'react-redux';
export const VkForm = () => {
const messages = useSelector((state: appStateType) => state.MessageReducer.Messages)
return (<div>
{messages.map((m) => {
<div key={m._id}>{m.text}</div>
})}
</div>)
}

This is a common mistake for beginners. You are missing the actual return statement in your .map function.
Since you are using curly brackets you have to explicity add the return statement before your JSX Component like:
{messages.map((m) => {
return <div key={m._id}>{m.text}</div>
})}
If you want to avoid explicitly returning that Component you can use the implicit return with parentheses:
{messages.map((m) => (
<div key={m._id}>{m.text}</div>
))}

Related

How do I properly use keys with React functional components? Here's my like button:

I'm trying build a Facebook-esque like button with React to get a better handle on stateful components. I'm not sure what the problem is, but I think it's the keys.
Error: Objects are not valid as a React child (found: object with keys {numLikes, onSelect}). If you meant to render a collection of children, use an array instead.
in p (at LikeButton.js:8)
in LikeButton (at App.js:10)
in App (at src/index.js:9)
in StrictMode (at src/index.js:8)
Here's App.js:
import React, { useState } from 'react';
import './App.css';
import LikeButton from './components/LikeButton';
function App() {
const [likes, updateLikes] = useState(23);
const [liked, updateLiked] = useState(false);
return (
<LikeButton
secret='like-button'
numLikes={likes}
// status={liked}
onSelect={(liked) => {
if (liked) {
updateLikes(likes + 1);
} else { updateLikes(likes - 1)
};
updateLiked(!liked);
}
}
/>
// onClick function here, or in LikeButton.js?
);
}
export default App;
Here's LikeButton.js:
import React from 'react';
import FaThumbsUp from 'react-icons/fa';
export default function LikeButton(secret, numLikes, onSelect) {
return (
<>
<div key={secret} onClick={onSelect}>Like Button</div>
<p>{numLikes}</p>
</>
);
}
When using properties in functional component you need to destruct the props, not take them individually. Because properties of a component are the first parameter in the function
import React from 'react';
import FaThumbsUp from 'react-icons/fa';
export default function LikeButton({secret, numLikes, onSelect}) {
return (
<>
<div key={secret} onClick={() => onSelect(true)}>Like Button</div>
<div key={secret} onClick={() => onSelect(false)}>Dislike Button</div>
<p>{numLikes}</p>
</>
);
}
When you get a error of this type, know that you are trying to render a property or variable that is not a React element or non-object type data.
secret, numLikes, onSelect are inside of props object. you should destruct before use.
const {secret, numLikes, onSelect} = props

Render prop as string or component with Typescript

I have a function that conditionally renders/returns a string or a dynamic component depending on what type the prop is:
const renderValue = (value: string | React.ReactNode) => {
if (React.isValidElement(value)) {
const Component = value
return <Component />
}
return value
}
However, with the above code I get the following message from Typescript:
JSX element type 'Component' does not have any construct or call signatures.ts(2604)
I have read other answers on this topic on SO, but still haven't concluded an answer.
<Component /> is JSX notation and it's basically telling React to render this component. That's only possible in React Component which has to return JSX code. To solve the problem you could just check if argument is valid element and then render it conditionally in desired React Component
import React from 'react'
interface Props {
value: string | React.ReactNode
}
const SomeComponent:React.FC<Props> = ({value}) => {
return (
<div>
<span>Hello World</span>
{React.isValidElement(value) ? <Component/> : value}
</div>
)
}

Understanding Module Scope in Nested React Components

While refactoring some code at work, I ran into a circular dependency with nested React components. The feature was basically "Use a switch to dynamically render components nested in other components, including themselves".
I solved the problem by creating a component "registry" with two methods, registerBlock and an HOC BlockRegistry.
src/BlocksNode.js
// src/BlocksNode.js - accepts and renders a block passed from the API
import BlockRegistry, { registerBlock } from './BlockRegister'
import ComponentOne from './ComponentOne'
import ComponentTwo from './ComponentTwo'
// accepts a name and a component
registerBlock('componentOne', ComponentOne)
registerBlock('componentTwo', ComponentTwo)
// reads a block from the API and uses the type passed from props
const BlocksNode = (props) => {
const { type, blocks } = props
return <BlockRegistry type={type} blocks={blocks} />
}
export default BlocksNode
src/BlockRegister.js
const components = {}
export function registerBlock(name, Component) {
components[name] = Component
}
const BlockRegistry = (props) => {
const { type, ...rest } = props
const Component = components[type]
return <Component {...rest} />
}
export default BlockRegistry
src/ComponentOne.js
import BlockRegistry from './BlockRegister'
function ComponentOne(props) {
const { blocks } = props
return (
<div>
{blocks.map((block) => {
const { type, blocks } = block
return <BlockRegistry type={type} blocks={blocks} />
})}
</div>
)
}
export default ComponentOne
ComponentOne.js can pass any number of other blocks, including ComponentTwo.js or itself. I've simplified some of the logic, but the gist is there.
This solution works great. But I don't understand how it's able to function. Logically I'd expect the nested component's scope to not include the top-level, registered components. How is scope being handled so that nested components are working without new, nested calls to registerBlock()?
For instance, how does <BlockRegistry /> in ComponentOne.js find a match for block.type === 'componentTwo'? I'd expect to need to re-register it, ie. by doing registerBlock('componentTwo', ComponentTwo) inside ComponentOne.js. The fact that it works without the call seems strange.

React inline functions rerender issue

I have a component that uses two nested components that are based on render prop pattern. I need to combine props from both of them to be sent to the innermost function.
<Component1>
{(...props1) => (
<Component2>
{(...props2) => <MyComponent {...props1} {...props2} />}
</Component2>
)}
</Component1>
Now, I wanted to refactor the above inline functions into class functions, so as to avoid creating new functions on every render.
First attempt:
render() {
return <Component1>{this._render1}</Component1>;
}
_render1 = (...props1) => <Component2>{this._render2}</Component2>;
_render2 = (...props2) => <MyComponent {...props1} {...props2} />;
But now, in render2, I don't have access to props1, so I did:
render() {
return <Component1>{this._render1}</Component1>;
}
_render1 = (...props1) => <Component2>{this._render2(...props1)}</Component2>;
_render2 = (...props1) => (...props2) => <MyComponent {...props1} {...props2} />;
But here, I am back again to original problem of recreating inline functions on each render (inside _render2).
Please suggest a way to mitigate this problem. How can I best send the combined data down? What am I doing wrong here?
Did you got a chance to take a look on React.Context (https://reactjs.org/docs/context.html)?
You can create something like:
SomeContext.jsx
import React from "react";
export const SomeContext = React.createContext();
index.jsx
<SomeContext.Provider value={this.state.contextState}>
<div>
....
<Component2 />
<MyComponent />
...
</div>
</SomeContext.Provider>
Component2.jsx / MyComponent.jsx
import React from "react";
import { SomeContext } from "./SomeContext";
export default () => (
<SomeContext.Consumer>
your jsx with access to the props from parent.
</SomeContext.Consumer>
);
Hope it helps you.

ReactJS using jquery for animations

I'm trying to render a component, but the value is inside a jQuery function that checks for changes in an input field.
The console returns this error:
Objects are not valid as a React child (found: [object HTMLDocument]).
If you meant to render a collection of children, use an array instead
or wrap the object using createFragment(object) from the React
add-ons. Check the render method of Result
the code:
import React, { Component } from 'react';
import Result from './Result';
import * as $ from 'jquery';
import ReactFM from '../lib/ReactFM';
import { config } from '../config';
export let reactfm = new ReactFM(config.apiKey);
let name = $(() => {
$('.input-search').keypress(() => {
let inp = $('.input-search').val();
return reactfm.searchArtists(inp);
});
});
class SearchResults extends Component {
render() {
return (
<div className="search-results">
<Result avatar="" name={name} desc="um deus" />
</div>
);
}
}
export default SearchResults;
There really is no good reason to use jQuery when you are using React.
If you are (and you should be) writing the html that contains the input element in JSX as a higher level React component, you can reference the input either by a ref attribute or add a keydown event listener to the input itself.
Example:
const HigherLevelParentComponent = React.createClass({
getDefaultState() {
searchQuery: ''
},
searchArtists(event) {
this.setState({
searchQuery: event.target.value
})
},
render() {
(
<div>
<input type="text" onKeyDown={(event) => this.searchArtists(event)}/>
<Result ... /> // You probably want this to be a mapped array of Result components with unique props instead
</div>
)
}
})
You will also want to include a function that searches through the searchable data and returns an array of objects that you could then render into Result components using mapping and props. How you do this will depend on where the searchable data is coming from (React store, database table on the back-end, etc.).
Also, you mentioned using jQuery for animations but did not elaborate.

Categories

Resources