Cannot read property 'company' of null - reactjs

console.log(profile); works well and it shows this.
but when I use console.log(profile.company); to get the company name.
it show me the Cannot read property 'company' of null error message.
how to solve this err? Any help is highly appreciated.
here is the code
import React,{Fragment,useEffect}from 'react'
import PropTypes from 'prop-types'
import Loading from "../layout/Loading.js"
import {connect} from "react-redux"
import {getProfileById} from "../../redux/profile/profileAction.js"
import { Link } from 'react-router-dom'
import ProfileTop from "./ProfileTop.js"
import ProfileAbout from "./ProfileAbout.js"
import ProfileExperience from "./ProfileExperience.js"
import ProfileEducation from "./ProfileEducation.js"
import ProfileGithub from "./ProfileGithub.js"
const Profile = ({getProfileById,match,profileData,loginData}) => {
const {loading,profile}=profileData
console.log(profile); //works
console.log(profile.company); //error occurred
useEffect(()=>{
getProfileById(match.params.userId)
},[getProfileById,match.params.userId])
return (
<div style={{marginTop:"100px"}}>
{
profile ===null||loading? (<Loading/>):
(<Fragment>
<Link to="/profiles" className="btn btn-light"> Back to profiles</Link>
{
(loginData.isAuthenticated && loginData.loading===false&&loginData.user_data.userid===match.params.userId) ?
(<Link to="/edit-profile" className="btn btn-dark">Edit profile</Link>):null
}
<div className="profile-grid my-1">
<ProfileTop profile={profile}></ProfileTop>
<ProfileAbout profile={profile}></ProfileAbout>
<ProfileExperience profile={profile}></ProfileExperience>
<ProfileEducation profile={profile}></ProfileEducation>
<ProfileGithub profile={profile}></ProfileGithub>
{
profile.github_user_name===""? null:<ProfileGithub profile={profile}></ProfileGithub>
}
</div>
</Fragment>)
}
</div>
)
}
Profile.propTypes = {
profileData:PropTypes.object.isRequired,
}
const mapStateToProps=(state)=>{
return{
profileData:state.profileData,
loginData:state.loginData
}
}
export default connect(mapStateToProps,{getProfileById})(Profile)

Cannot read property 'company' of null error message
It is clear that the 'company' object is null (might be for the initial render)
and you are getting the error because you are accessing the property on the null object.
In the case of TypeScript you can use,
profile?.company.
It is called optional chaining
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining
but in the normal JS, we have to use if statement and check for null case.
For the above example your template is completely depends on the profile.
So that initially itself check the value of profile, if the value is undefined/null then return an empty template.
if(!profile){
return null;
}
return <Your template>

As mentioned in the comments, browser consoles will not print the content of an object right away. To do so you would need to do something such as JSON.stringify(profile).
Also, it's perfectly fine to console.log on functional components in my opinion, this will let you know when components render (but don't get too caught up in why components render so often, renders are usually not expensive).
If you are using a recent version of Create React App, you can try optional chaining (?.):
console.log(profile);
console.log(profile?.company); // equivalent to (profile && profile.company)
// Or if you need to know the content exactly in the moment:
console.log(JSON.stringify(profile));

Related

React: Client & Server way to render children to string

How can I render the children as a string in React 18/Next 13?
React says renderToString is not suggested on the client, and it's not clear to me how to render it on the server.
The documentation here gives an example but it's not clear how it works in an actual react component as I get errors that I cannot create another node if the previous one wasn't removed from the head.
import { createRoot } from 'react-dom/client';
import { flushSync } from 'react-dom';
const div = document.createElement('div');
const root = createRoot(div);
flushSync(() => {
root.render(<MyIcon />);
});
console.log(div.innerHTML); // For example, "<svg>...</svg>"
Source
Whether I get the data on the server or client side, just looking for a working example either or.
function ExampleChildComponent() {
return (
<div className="bg-green-500 w-20 h-20">
Hello I am a green box
<button className="bg-blue-100 px-6 py-3">I am a button</button>
</div>
)
}
function LogChild({ children }: any) {
// How do you get the children to a string?
console.log(someFn(children));
// Interested in both an output showing <GreenBox />
// and/or the parsed version which shows the stuff inside GreenBox
return (
<p>Logged!</p>
)
}
function App(){
return (
<LogChild>
<ExampleChildComponent />
</LogChild>
)
}
Alternatively, if there's an open source project that I can just study works too. Google is very sparse in examples for this question. Either that or answers are pre React 18.

Error Hydration failed with react-speech-recognition

I wanted to try speech recognition in NextJS 13. I installed react-speech-recognition and copy/pasted the provided example. But I am getting Error: Hydration failed because the initial UI does not match what was rendered on the server.
I tried to rollback react to v18.1, removed .next folder but it didn't help. I scrolled NextJS documentation about React Hydration Error, but I don't call windows and don't put div tag in p.
Any ideas what can be the issue?
Code:
'use client'
import 'regenerator-runtime/runtime'
import React from 'react'
import SpeechRecognition, {
useSpeechRecognition,
} from 'react-speech-recognition'
export default function page() {
const {
transcript,
listening,
resetTranscript,
browserSupportsSpeechRecognition,
} = useSpeechRecognition()
if (!browserSupportsSpeechRecognition) {
return <span>Browser doesn't support speech recognition.</span>
}
return (
<div>
<p>Microphone: {listening ? 'on' : 'off'}</p>
<button onClick={SpeechRecognition.startListening}>Start</button>
<button onClick={SpeechRecognition.stopListening}>Stop</button>
<button onClick={resetTranscript}>Reset</button>
<p>{transcript}</p>
</div>
)
}
The hydration error is caused by these lines:
if (!browserSupportsSpeechRecognition) {
return <span>Browser doesn't support speech recognition.</span>
}
Because you are using the 'use client' directive, this component behaves as traditional page components on previous Next.js versions (The page is pre-rendered and then sent to the client to be hydrated). The library you are using checks if webkitSpeechRecognition or SpeechRecognition exists in the window object in order to set the browserSupportsSpeechRecognition boolean, but window is not available server-side (it is undefined). The condition above evaluates to true thus creating the mismatch between what was rendered on the server and on the client-side's first render (You can view the page's source and you will notice that the not supported text was rendered on the server).
You can solve the issue using useState and useEffect hooks, taking advantage of the fact that useEffect only runs on the client-side:
'use client'
import React, { useState, useEffect } from 'react'
import 'regenerator-runtime/runtime'
import SpeechRecognition, {
useSpeechRecognition
} from 'react-speech-recognition'
const Page = () => {
const [speechRecognitionSupported, setSpeechRecognitionSupported] =
useState(null) // null or boolean
const {
transcript,
listening,
resetTranscript,
browserSupportsSpeechRecognition
} = useSpeechRecognition()
useEffect(() => {
// sets to true or false after component has been mounted
setSpeechRecognitionSupported(browserSupportsSpeechRecognition)
}, [browserSupportsSpeechRecognition])
if (speechRecognitionSupported === null) return null // return null on first render, can be a loading indicator
if (!speechRecognitionSupported) {
return <span>Browser does not support speech recognition.</span>
}
return (
<div>
<p>Microphone: {listening ? 'on' : 'off'}</p>
<button onClick={SpeechRecognition.startListening}>Start</button>
<button onClick={SpeechRecognition.stopListening}>Stop</button>
<button onClick={resetTranscript}>Reset</button>
<p>{transcript}</p>
</div>
)
}
export default Page
I had the same problem, but I think checking for server rendering (when the window object is undefined) is a little bit less messy solution:
const isServer = typeof window === "undefined";
if (!browserSupportsSpeechRecognition && !isServer) {
return <div>Your browser does not support speech recognition.</div>;
}
Works well!

How to show the correct component according to the user types

I have two different user type in my react project normal user and admin but to specify that I am not using any database. So I connect metamask wallet and I am getting and the wallet (you can think as an Id) and if the wallet is equal something it is admin, otherwise it is normal user. in localStorage I am keeping if the admin is true or false and according to that I want to show or . But first there is something wrong with my if statement, because all the time it shows (even in localStorage admin is false) and second it is not real time rendering. So what I am expecting, when the user type is changed, it the project rerenders and show the correct component. Here is my component:
import React, { useEffect } from "react";
import { Container, Row, Col } from "react-bootstrap";
import Twitch from "../Twitch/Twitch";
import AdminGame from "./AdminGame";
import "./Game.css";
import UserGame from "./UserGame";
const Game = () => {
useEffect(() => {
if (
localStorage.getItem("walletId") ==
""
) {
localStorage.setItem("admin", true);
} else {
localStorage.setItem("admin", false);
}
}, [localStorage.getItem("walletId")]);
return (
<section id="game">
<Container>
<Row>
<Col>
{localStorage.getItem('admin') ? <UserGame /> : <AdminGame/>}
</Col>
</Row>
</Container>
</section>
);
};
export default Game;
Container and Row tags are React Bootstrap based so dont worry about them. But I wonder rest of my logic is correct and why it doesnt rerender.
you should do JSON.parse so that your evaluation is correct.
{JSON.parse(localStorage.getItem("admin")) ? <AdminGame /> : <UserGame />}

Why is react skeleton not rendering?

I have a component Recommended that makes a service call to firebase and renders the returned data. During the loading delay at the database call, I want to render a react skeleton, as follows:
Recommended.js
import { useState, useEffect } from "react";
import Skeleton from "react-loading-skeleton";
import { getVenues } from "../services/firebase";
import VenueCard from "./VenueCard";
const Reccomended = () => {
const [venues, setVenues] = useState([]);
useEffect(() => {
async function getAllVenues() {
const response = await getVenues();
await setVenues(response);
}
getAllVenues();
}, []);
venues[0] ? console.log(true) : console.log(false)
return (
<div>
{!venues[0] ? (
<>
<Skeleton />
</>
) : (
<>
<p className="recommended">Recommended for Josh</p>
<VenueCard venues={venues} />
</>
)}
</div>
);
};
export default Reccomended;
However, the skeleton is not rending during loading. The returning data is saved to the state variable venues, and I'm using the 'truthiness' as a conditional for the render. I tested this by logging the following:
venues[0] ? console.log(true) : console.log(false)
In the browser it initially logged false, followed quickly by true
So given this, I don't understand why the skeleton isn't loading - any suggestions?
I've also passed parameters into <Skeleton/> which didn't change anything.
You must include the CSS styles, or you won't see anything. Just add
import "react-loading-skeleton/dist/skeleton.css";
with the rest of the imports.
This is documented in the package readme in the react-loading-skeleton basic Usage section

React How to pass arguments to function

Hi I found a question asking the same thing but they coded completely different using 'class name extends', I am just using 'function name'. I was wondering how I would I solve this problem or do I have to rewrite my program.
I have styles at the bottom I left off.
Window.js
import React from 'react';
import "../css/Start.css";
export default function Window(nuts) {
let ulList=[]
for (let i=0;i<nuts.file.length;i++) {
ulList.push(<li>
{
nuts.file[i]
}
</li>)
}
let imageList=[]
for (let i=0;i<nuts.image.length;i++) {
imageList.push(<img src={nuts.image[i]} alt={nuts.image[i]}/>)
}
return (
<div style={main}>
<p>{nuts.name}</p>
<p>{nuts.date}</p>
<p>{nuts.note}</p>
{ulList}
{imageList}
<button> Demo </button>
</div>
);
}
Project.js
import React from 'react';
import Background from '../images/projectbackground.jpg';
import "../css/Start.css";
import Window from './Window'
export default function Project() {
const files = ['f1','f2','f3']
const images = ['p1','p2','p3']
const nuts = {name:'phil',date:'2/2/16',note:'this is a note',file:files,image:images}
return (
<div style={main}>
<Window nuts={nuts}/>
<div style={footer}>
</div>
</div>
);
}
Your function component will get passed all the properties together in an object.
There are three changes you could make to have this work:
render <Window {...{nuts}} /> instead (not recommended but is an option)
change parameters to function Window(props) and all your other code to say props.nuts instead of just nuts
change parameters to function Window({nuts}) to destructure the (no longer named) "props" object
nuts is being passed to Window via the props object.
You either need to destructure nuts in-line or in your function body.
function Window({ nuts })
or
function Window(props) {
const { nuts } = props;
}

Resources