React App is giving error when using context API - javascript

I am learning React and right now trying to implement the old way of working with Context API but when I try to compile I get an error.
It says :
TypeError: context is undefined. Version is 17.0.1
Here are the files I use:
Test0.js
import React from 'react';
const Test0 = React.createContext();
export default Test0;
Test1.js
import React, { Component } from 'react';
import Test0 from './Test0';
class Test1 extends Component{
render(){
return (
<Test0.Consumer>
{context => (<p>This is {context.name}</p> )}
</Test0.Consumer>
);
}
}
export default Test1;
Test2.js
import React, { Component } from 'react';
import Test0 from './Test0';
import Test1 from './Test1';
class Test2 extends Component{
state = {
name: 'James',
age : 30
}
render(){
return (
<Test0.Provider
value={{
name : this.state.name,
age: this.state.age
}}
>
<Test1 />
</Test0.Provider>
);
}
}
export default Test2;
I then render <Test1 /> in app.js

I then render < Test1 /> in app.js
You need to render Test2 because you define your Context Provider there. Below is the link for the full working code.
CODESANDBOX LINK: https://codesandbox.io/s/context-api-issue-lqkv8

You're using Test1 component which consumes Test0, a context, that you suppose to provide values, but in Test0 you're providing no value. You wrongly implemented the provider in separate Component, Test2, that you don't render so Test0 doesn't know about the provided values and it's assuming you didn't define the context.

Related

Functional component to class component Error: Cannot read property 'id' of undefined

I'm working on a small project and am in the process of translating a functional component to a class based component so that my component can manage its state. In translating the component over, I've run into an error:
TypeError:Cannot read property 'id' of undefined
This component worked as a functional component so I'm not sure why I'm receiving this error now. Can anyone answer why in translating from a functional component to a class based one that I'm receiving this error? Is this something to do with scope at all? Do I just have some syntax wrong? I've been banging my head against this for a while and just can't understand why it cannot read the property of 'id' which is in now in the return of the render portion of my component.
Component code:
import React, {Component} from "react";
import "./OpenTasksComponent.css"
class openTasks extends Component{
constructor(){
super();
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
let x = document.body.nodeName;
console.log(x);
}
render(){
return (
<div className="tasks" value = {this.task.id}>
<h1 onClick={this.handleClick}>{this.task.clientName}</h1>
<div className="accordion-item accordion-item-open">
<h2>{this.task.matter}</h2>
<p>{this.task.matterStatus}</p>
</div>
</div>
)
}
}
export default openTasks
App code:
import './App.css';
import Task from './components/open-tasks-component/open-tasks-component';
import tasksData from './components/open-tasks-component/tasks-data';
import Header from './Header';
function App() {
const Tasks = tasksData.map(task=> <Task key={task.id} task ={task}/>)
return (
<div className="App">
<Header />
{Tasks}
</div>
);
}
export default App;
In App you passed a prop down, but you tried to read it in the child class component using this.task.id it should be this.props.task.id
Functional components can also manage states.
You can use useState.
const [state, setState] = useState(null);

React context between unrelated components

For learning purposes I'm just trying to render this dumb example where Component A has a variable that creates a random number and another (unrelated) Component B can render it with useContext. I don't know how to make the provider of the context to know that the value is the variable from Component A.
I created another file to do the React.createContext()... but still don't know how to make the random number to reach there or the App Component to do the Provider. I know I could create the random number in App component and provide whatever component I want with that value, but I just want the value to be generated in Component A and reach Component B. Any ideas? Maybe its so simple I can't see it.
What I have at the moment:
Component A:
import React from'react';
export default function RandomNumGenerator() {
const randomNum = Math.random();
return(
<h2>Your random number is:</h2>
)
}
Component B:
import React from'react';
export default function RandomNumRenderizator() {
return(
<h2></h2> //Want to render the random num here
)
}
App Component:
import React from 'react';
import RandomNumGenerator from "./FunctionalComponents/RandomNumGenerator/RandomNumGenerator";
import RandomNumRenderizator from "./FunctionalComponents/RandomNumRenderizator/RandomNumRenderizator";
import RandomNumContext from "./contexts/RandomNumContext";
export default function App() {
return (
<div>
<RandomNumGenerator/>
<RandomNumContext.Provider value={}> //Empty value as I don't know what to send
<RandomNumRenderizator/>
</RandomNumContext.Provider>
</div>
);
}
And the Context:
import React from "react";
const RandomNumContext = React.createContext(); //Don't know if there should be anything as defaultValue
export default RandomNumContext;
As data flows down in React, the value you wish to pass have to be in scope with the context provider, then you just need to read the context value using a hook:
export default function App() {
const randomNum = Math.random();
return (
<>
<RandomNumDisplay num={randomNum} />
<RandomNumContext.Provider value={randomNum}>
<RandomNumRenderizator />
</RandomNumContext.Provider>
</>
);
}
export default function RandomNumRenderizator() {
const randomNum = useContext(RandomNumContext);
return <h2>{randomNum}</h2>;
}

How to preserve referencies when Component is exported via a function?

Documentation describes how to add a ref to a class component when using ReactJS version 16.3+.
Here is a simplified and working example using two files:
MyForm.js file:
import React, { Component } from 'react';
import MyInput from "./MyInput";
class MyForm extends Component {
constructor(props) {
super(props);
this.myInput = React.createRef();
this.onClick = this.onClick.bind(this);
}
onClick(){
console.log(this.myInput.current.isValid());
}
render() {
return (
<div>
<MyInput ref={this.myInput} />
<button onClick={this.onClick}>Verify form</button>
</div>
);
}
}
export default MyForm;
MyInput.js file
import React, { Component } from 'react';
class MyInput extends Component {
isValid(){
return true;
}
render() {
return (
<div>
Name :
<input type="text" />
</div>
);
}
}
export default MyInput;
It works fine, console displays true when I click on MyForm button. But as soon as I add a function just before exporting my Component, errors are thrown. As example, I add a translation via react-i18n
MyInput.js file with export using a function
class MyInput extends Component {
isValid(){
return true;
}
render() {
const {t} = this.props;
return (
<div>
{t("Name")}
<input type="text" />
</div>
);
}
}
export default translate()(MyInput); // <=== This line is changing
Now, when I click on button, an error is thrown:
TypeError: this.myInput.current.isValid is not a function
The error disappear when I remove translate() in the last line.
I understood that the ref has been destroyed by the new component returned by translate function. It's an HOC. I read the Forwarding ref chapter, but I don't understand how to forward ref to the component returned by translate() function.
I have this problem as soon as I use translate from reacti18next and with the result of connect function from redux
I found a solution using onRef props and ComponentDidMount, but some contributors thinks this is an antipattern and I would like to avoid this.
Is there a way to create a wrapper that catch the HOC result of translate() or connect() and add ref to this HOC result ?

How can pass a props to a variable?

I'm trying "hydrate" props from elements to child components that will render. The problem is that I can't figure out how I can do it with my configuration.
I have seen this answer, I tried to adapt it, but so far I'm getting errors (see bottom).
For a bit of background, I'm developing a Rails based application that uses React for the front end. So I don't use React router or such, it just "displays" the datas.
Here is how I set everything up:
front.js (where everything gets rendered)
import React from 'react';
import ReactDOM from 'react-dom';
import extractActionName from './lib/extractActionName';
import {elementForActionName} from './lib/elementForActionName';
import 'jquery';
import 'popper.js';
import 'bootstrap';
let actionName = extractActionName();
let value = "value";
let renderElement = function (Element, id) {
ReactDOM.render(
<Element value={value} />,
document.getElementById(id)
);
};
renderElement(elementForActionName[actionName], actionName);
lib/elementForActionName.js
import React from 'react';
import Homeindex from '../home/home';
import Contact from '../home/contact';
// This files create an associative array with id React will be
// looking for as a key and the component as value
export const elementForActionName = {
'index': <Homeindex />,
'contact': <Contact/>,
};
lib/extractActionName.js
export default function extractActionName() {
// The body contains classes such as "home index", so
// I return the "action name" of my controller (home) to
// front.js so I will render the good component
return document.body.className.split(' ').pop();
}
home/home.js
import React from 'react';
import Header from '../layout/header';
import Footer from '../layout/footer';
export default class homeIndex extends React.Component {
render() {
return(
<div>
<Header/>
<h1>Hello this will be the content of the landing page hello</h1>
<Footer/>
</div>
)
}
}
My problem is that I'd like to make an Ajax call in my "front.js" file, then transmit the received data (here, "value"). The error I'm getting is the following:
Uncaught Error: Element type is invalid: expected a string (for
built-in components) or a class/function (for composite components)
but got: object.
I'm lacking experience with React, how can I resolve this problem?
Thank you in advance.
You are currently returning the instance of a component:
export const elementForActionName = {
'index': <Homeindex />, <--- here
'contact': <Contact/>,
};
And then attempting to instantiate it again:
let renderElement = function (Element, id) {
ReactDOM.render(
<Element value={value} />, // <--- here
document.getElementById(id)
);
};
Instead, just use the component class:
export const elementForActionName = {
'index': Homeindex,
'contact': Contact,
};

Exporting functions with reactjs and babel

I have a project using reactjs, which is transpiled by babel. I use the es2015 and react transforms in my .babelrc. I am currently refactoring and in my first pass I basically did export class foo for everything I needed. A lot of these classes should really just be functions, so I am trying to rewrite them as such, but I keep getting the same error. My main application file looks somethings like this:
import React, { Component } from 'react';
import {Foo, Bar} from './components/ui.js';
class Application extends Component {
constructor(props){
super(props);
this.state = {
object: null
}
}
componentDidMount(){
// code
}
componentDidUpdate(){
// other code
}
render(){
return(
<div>
<Foo />
<Bar />
</div>
)
}
}
module.exports = Application
And my import from ui.js is like this:
import React, { Component } from 'react';
export class Foo extends Component {
constructor(props){
super(props);
}
render() {
return (
// Some JSX
)
}
}
export class Bar extends Component {
constructor(props){
super(props);
}
render() {
return (
// Some other JSX
)
}
}
When I try and change one of these exported classes to a function, for example:
// Note: I have tried a variety of syntax such as function, const, etc...
export var Bar {
render() {
return (
// Some other JSX
)
}
}
I get the following error:
SyntaxError: Unexpected token <line where I declare a function>
I am not sure what I am doing wrong, and my google searches are only coming up with answers to other problems.
It's the same as defining the function as a variable but just adding export to the front e.g. (using ES6 syntax)
export const render = () => (
// Some other JSX
);
or alternatively
export var render = function() {
return (
// Some other JSX
);
};
Exporting functions is no different than exporting class. Basic rules must be followed .
Function/Class name should in CAPS
There will be only one "export" line .
Every function return body should have a single tag encompassing other parts. Most commonly used is a tag .
This usually works: import App from "./App"; where App.js is my jsx file.
You can do an explicit import too . : import AllApp from "./classhouse.jsx";
Name of the js/jsx file does not matter. It can be anycase (lower, upper).
For returning multiple functions from one file, you need to create one more function , that encompasses all other functions .
See the example below showing multiple functions returned.
import React from 'react';
/* All function / class names HAS TO BE in CAPS */
var App1 = function (){
return (
<div>
<h1>
Hello World
</h1>
</div>
)
}
var App2 = function (){
return (
<div>
<h1>World Number 2 </h1>
</div>
);
}
var AllApp = function (){
return (
<div>
<App1 />
<App2 />
</div>
);
}
export default AllApp;
My index.js file:
import React from 'react';
import ReactDOM from "react-dom";
import AllApp from "./classhouse.jsx"; /* Note: App name has to be in CAPS */
import App from "./App";
const jsx =
<div>
<AllApp />
<App />
</div>
ReactDOM.render(jsx, document.getElementById("root"));
You are writing functional components in wrong way.
function Welcome() {
return <h1>Hello World</h1>;
}
or
const Welcome = () => {
return <p>Hello Wrold</p>
}
export default Welcome ;
ES6 doesn't allow export default const. You must declare the constant first then export it.

Categories

Resources